React中多个Collapsible组件实例疑似共享状态,点击第二个第一个展开原因是什么?
问题根源
你遇到的错位展开问题是多个因素共同导致的,按优先级排序如下:
- 首要原因:
Collapsible组件没有将传入的open属性绑定到内容区的显隐逻辑上,你当前代码里的Content、InnerContent完全没有根据open值调整展示状态,如果你的显隐逻辑依赖CSS选择器,DOM结构和选择器的匹配错误会导致状态命中到相邻组件的内容区。 - 次要原因:使用数组下标作为列表
key,如果FAQ列表后续有增删排序操作,会导致React复用错误的组件实例,出现状态错位;如果FAQ存在重复的question值,也会导致展开判断openFAQ === question命中多个组件。
解决方案
1. 补全Collapsible的内容显隐逻辑
根据你的交互需求选择两种实现方式:
不需要动画效果的条件渲染方案:
export const Collapsible = ({ title, open, children, onClick, ...props }: Props) => { return ( <Container {...props}> <Toggle open={open} /> <Title onClick={onClick}>{title}</Title> {/* 仅open为true时渲染内容 */} {open && <Content> <InnerContent>{children}</InnerContent> </Content>} </Container> ); };
需要动画效果的CSS控制方案:
给Content组件传递open属性,在样式中绑定显隐逻辑,以styled-components为例:
// 样式定义 const Content = styled.div<{open: boolean}>` height: 0; overflow: hidden; transition: all 0.3s ease; ${({open}) => open && ` height: auto; padding: 12px 0; `} ` // 组件调用 <Content open={open}> <InnerContent>{children}</InnerContent> </Content>
2. 替换列表key值、改用唯一ID判断展开状态
避免question重复或数组变化导致的状态错位,建议给每个FAQ项增加唯一ID字段:
// 调整FAQS结构,增加唯一id const FAQS = [ {id: 'faq_001', question: '问题1', answer: '回答1'}, {id: 'faq_002', question: '问题2', answer: '回答2'}, // 其余项 ] // 状态逻辑调整为用ID判断 const [openFAQ, setOpenFAQ] = React.useState<string | null>(null); const handleFAQClick = (id: string) => { setOpenFAQ(prev => prev === id ? null : id); }; // 渲染时用id作为key和判断依据 return ( FAQS.map(({ id, question, answer }) => ( <Collapsible key={id} title={question} open={openFAQ === id} onClick={() => handleFAQClick(id)} > {answer} </Collapsible> )) )
内容的提问来源于stack exchange,提问作者artooras
相关产品推荐
相关产品推荐

