React中useState影响同一组件多实例的问题及修复方法
问题:React组件批量渲染后点击展开按钮所有实例同步展开
我基于useState实现了一个点击按钮展开指定区域的组件,但通过map渲染多个组件实例后,点击其中一个的展开按钮,所有实例都会跟着展开。
我的组件代码:
const ContainerMenu: React.FC<ContainerMenuProps> = (props: ContainerMenuProps) => { const [expanded, setExpanded] = useState(false); return ( <> <div className={`docker-container-menu ${expanded}`}> <button onClick={() => setExpanded(!expanded)} className='chevron-button'> <Icon path={mdiChevronDown} size={1} /> </button> {expanded && <div className='docker-container-menu-expanded'> <button style={{ cursor: "pointer" }} onClick={() => props.startContainer(props.Id)}> <Icon style={{color: "green"}} path={mdiPlay} size={1} /> </button> <button style={{ cursor: "pointer" }} onClick={() => props.stopContainer(props.Id)}> <Icon style={{color: "red"}} path={mdiStop} size={1} /> </button> </div>} </div> </> ) }
列表渲染代码(已传递唯一Id作为props):
return ( <> <div className="app-main-container"> <div className="docker-containers"> {containers.map((container: ContainerProps) => { return ( <Container Id={container.Id} State={container.State} Status={container.Status} Names={container.Names} Labels={container.Labels}/> ) })} </div> </div> </> )
解决方法
1. 给列表项添加唯一key属性
React在渲染列表时需要通过唯一key区分不同组件实例,缺少key会导致React复用组件,引发状态混乱。修改列表渲染代码:
{containers.map((container: ContainerProps) => { return ( <Container key={container.Id} Id={container.Id} State={container.State} Status={container.Status} Names={container.Names} Labels={container.Labels} /> ) })}
2. 优化类名拼接逻辑
原代码中直接将布尔值expanded作为类名,会生成docker-container-menu true这类不规范的类名,建议转为字符串类名:
const ContainerMenu: React.FC<ContainerMenuProps> = (props: ContainerMenuProps) => { const [expanded, setExpanded] = useState(false); return ( <> <div className={`docker-container-menu ${expanded ? 'expanded' : ''}`}> <button onClick={() => setExpanded(!expanded)} className='chevron-button'> <Icon path={mdiChevronDown} size={1} /> </button> {expanded && <div className='docker-container-menu-expanded'> <button style={{ cursor: "pointer" }} onClick={() => props.startContainer(props.Id)}> <Icon style={{color: "green"}} path={mdiPlay} size={1} /> </button> <button style={{ cursor: "pointer" }} onClick={() => props.stopContainer(props.Id)}> <Icon style={{color: "red"}} path={mdiStop} size={1} /> </button> </div>} </div> </> ) }
原因说明
- 缺少
key时,React无法识别列表中每个组件的唯一性,会复用已有组件实例,导致单个组件的状态变化被同步到所有实例。 - 规范类名拼接可以避免样式逻辑出现意外问题,确保展开样式正确生效。
内容的提问来源于stack exchange,提问作者Brenden Crowie
相关产品推荐
相关产品推荐

