You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React自定义隐藏单选按钮点击后样式重复问题求助

问题描述

我有两个自定义的隐藏单选按钮组件,点击标签时单选按钮会被选中。我给选中状态的标签加了样式(带内边距的边框和背景),但现在的问题是,点击另一个单选按钮的标签时,两个标签都会显示选中样式,尽管实际上只有一个单选按钮处于选中状态。

父组件代码

<div className="flex lg:justify-center gap-2 lg:gap-6">
    <EspaceCard
        value="miami"
        onChange={(e) =>
            setValues((prev) => ({ ...prev, espace: e.target.value }))
        }
        checked={values.espace === 'miami'}
        text="MIAMI ROOM"
    />
    <EspaceCard
        onChange={(e) =>
            setValues((prev) => ({ ...prev, espace: e.target.value }))
        }
        value="jungle"
        checked={values.espace === 'jungle'}
        text="JUNGLE ROOM"
    />
</div>

子组件(EspaceCard)代码

'use client'

import { ChangeEvent, useState } from 'react';

interface InputProps {
    text: string;
    value: string;
    checked?: boolean;
    onChange: (e: ChangeEvent<HTMLInputElement>) => void;
}

const EspaceCard = ({ text, value, onChange, checked }: InputProps) => {
    const [clicked, setClicked] = useState(checked);
    
    return (
        <>
            <label
                htmlFor={text}
                onClick={() => setClicked(!clicked)}
                className={`p-4 rounded-lg ${
                    clicked ? 'border-gold border bg-light-gold' : ''
                }`}
            >
                <div className="box-border lg:w-52 text-center relative bg-black px-6 py-6 h-60 rounded-xl shadow-lg lg:hover:scale-110 transition-all cursor-pointer border-gold border-4 before:content-[''] before:absolute before:top-0 before:left-1/2 before:bg-gold before:h-2 before:rounded-b-full before:w-1/2 before:-translate-x-1/2 grid place-content-center">
                    <p className="text-xl lg:text-2xl font-bold text-gold">{text}</p>
                </div>
            </label>
            <input
                type="radio"
                id={text}
                name="espace"
                value={value}
                onChange={onChange}
                checked={checked}
                hidden
            />
        </>
    );
};
export default EspaceCard;
解决方案

问题根源在于子组件内部维护的clicked状态和父组件传入的checked属性不同步。当父组件切换选中状态时,子组件的本地状态不会自动更新,导致旧的选中样式无法清除。

直接移除子组件的本地状态,完全依赖父组件传入的checked控制样式即可解决问题:

'use client'

import { ChangeEvent } from 'react';

interface InputProps {
    text: string;
    value: string;
    checked?: boolean;
    onChange: (e: ChangeEvent<HTMLInputElement>) => void;
}

const EspaceCard = ({ text, value, onChange, checked }: InputProps) => {
    return (
        <>
            <label
                htmlFor={text}
                className={`p-4 rounded-lg ${
                    checked ? 'border-gold border bg-light-gold' : ''
                }`}
            >
                <div className="box-border lg:w-52 text-center relative bg-black px-6 py-6 h-60 rounded-xl shadow-lg lg:hover:scale-110 transition-all cursor-pointer border-gold border-4 before:content-[''] before:absolute before:top-0 before:left-1/2 before:bg-gold before:h-2 before:rounded-b-full before:w-1/2 before:-translate-x-1/2 grid place-content-center">
                    <p className="text-xl lg:text-2xl font-bold text-gold">{text}</p>
                </div>
            </label>
            <input
                type="radio"
                id={text}
                name="espace"
                value={value}
                onChange={onChange}
                checked={checked}
                hidden
            />
        </>
    );
};
export default EspaceCard;

原理说明

  • 单选按钮的选中状态完全由父组件的values.espace统一管理,子组件仅根据checked属性渲染对应样式,无需本地状态。
  • 点击标签会自动触发隐藏单选按钮的onChange事件,父组件更新状态后,两个子组件的checked属性会分别同步为true和false,样式随之正确切换。

内容的提问来源于stack exchange,提问作者user19297279

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 23:45:38