You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在React中使用Active States操作div实现手风琴菜单单独开闭

问题根源

你现在遇到同步开合的问题主要来自两个错误设计:

  • setActive、setHeight都是组件全局共享的状态,所有手风琴项都读同一个全局值,自然会同步变化
  • 单个content ref在循环渲染时会被后渲染的项覆盖,无法对应到每个手风琴内容区

优化方案

你不需要额外的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.20 16:45:04