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
相关产品推荐
相关产品推荐

