如何在React中使用Active States操作div实现手风琴菜单单独开闭
问题根源
你现在遇到同步开合的问题主要来自两个错误设计:
setActive、setHeight都是组件全局共享的状态,所有手风琴项都读同一个全局值,自然会同步变化- 单个
contentref在循环渲染时会被后渲染的项覆盖,无法对应到每个手风琴内容区
优化方案
你不需要额外的setActive、setHeight状态和content ref,仅靠已经定义的activeItem就能完成所有逻辑,判断当前项的id是否等于激活id就可以区分状态,修改后的代码如下:
import { useState } from 'react'; const Accordion = () => { const accordionItems = [ { id: 'menu1', text: 'text from the first menu' }, { id: 'menu2', text: 'text from the second menu' }, { id: 'menu3', text: 'text from the third menu' }, ]; // 仅保留该状态存储当前激活的项id即可 const [activeItem, setActiveItem] = useState(null); const toggleAccordion = (currentId) => { // 点击已激活的项则设为空实现收起,否则切换为当前点击的项id setActiveItem(activeItem === currentId ? null : currentId); }; return ( <div className="my_list"> {accordionItems.map((p) => { const isActive = activeItem === p.id; return ( // 循环渲染必须加唯一key属性 <div className="accordion__section" key={p.id}> <button className={`accordion ${isActive ? 'active' : ''}`} onClick={() => toggleAccordion(p.id)} > <p className="accordion__title">{p.id}</p> </button> <div style={{ maxHeight: isActive ? '100px' : '0px' }} className={`accordion__content ${isActive ? 'active' : ''}`} > <div className="accordion__text"> {p.text} </div> </div> </div> ); })} </div> ) };
补充说明
- 如果需要支持同时展开多个项,可以把
activeItem改成数组类型,存储所有激活的id,点击逻辑调整为往数组中增删对应id即可 - 要实现平滑展开收起效果,直接给
.accordion__content类添加transition: max-height 0.3s ease属性即可
内容的提问来源于stack exchange,提问作者jibreal
相关产品推荐
相关产品推荐

