React按钮组如何实现点击单按钮时其余按钮自动取消激活态?
核心解决思路
你现在的问题是激活状态存在单个ActiveBtn内部,每个按钮的状态独立,自然没法实现互斥效果。只要把激活状态提升到所有按钮的共同父组件层级,用唯一标识(索引/自定义id/按钮名)记录当前激活的按钮,而不是用布尔值存单个按钮的激活状态,就可以实现点一个其他自动取消激活的效果。
步骤1:改造ActiveBtn组件,把状态相关属性提到props
interface ActiveBtnProps { // 按钮唯一标识 btnId: string | number // 父组件传入的当前是否激活状态 isActive: boolean // 点击触发的回调,把当前按钮id传给父组件 onActiveChange: (btnId: string | number) => void children: React.ReactNode } const ActiveBtn: React.FunctionComponent<ActiveBtnProps> = (props) => { const handleClick = () => { props.onActiveChange(props.btnId) } return ( <Button variant={props.isActive ? 'tertiary-active' : 'tertiary'} onClick={handleClick} > {props.children} </Button> ) }
步骤2:在业务父组件里维护激活状态
const BusinessPage: React.FunctionComponent = () => { // 状态存当前激活的按钮id,初始值可以设为默认激活的按钮id,没有就设为null const [activeBtnId, setActiveBtnId] = React.useState<string | number>('btn1') return ( <div className="btn-group"> <ActiveBtn btnId="btn1" isActive={activeBtnId === 'btn1'} onActiveChange={setActiveBtnId} > 按钮1 </ActiveBtn> <ActiveBtn btnId="btn2" isActive={activeBtnId === 'btn2'} onActiveChange={setActiveBtnId} > 按钮2 </ActiveBtn> <ActiveBtn btnId="btn3" isActive={activeBtnId === 'btn3'} onActiveChange={setActiveBtnId} > 按钮3 </ActiveBtn> </div> ) }
更优的封装方式
如果多个场景都要用到按钮组互斥效果,可以直接封装通用的ButtonGroup组件,把状态逻辑内置,业务方直接传配置即可:
interface ButtonGroupItem { id: string | number content: React.ReactNode } interface ButtonGroupProps { items: ButtonGroupItem[] defaultActiveId?: string | number onChange?: (activeId: string | number) => void } const ButtonGroup: React.FunctionComponent<ButtonGroupProps> = (props) => { const [activeId, setActiveId] = React.useState(props.defaultActiveId ?? null) const handleChange = (id: string | number) => { setActiveId(id) props.onChange?.(id) } return ( <div className="btn-group"> {props.items.map(item => ( <Button key={item.id} variant={activeId === item.id ? 'tertiary-active' : 'tertiary'} onClick={() => handleChange(item.id)} > {item.content} </Button> ))} </div> ) }
业务方调用非常简洁:
<ButtonGroup items={[ {id: 'btn1', content: '按钮1'}, {id: 'btn2', content: '按钮2'}, {id: 'btn3', content: '按钮3'}, ]} defaultActiveId="btn1" onChange={(id) => console.log('当前激活按钮', id)} />
内容的提问来源于stack exchange,提问作者Sole
相关产品推荐
相关产品推荐

