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

如何使用React Hooks单独切换accordion手风琴面板?

手风琴单独切换解决方案

问题原因

你的代码存在3个核心问题导致所有面板同步切换:

  • 所有面板共用了全局的激活状态、高度、旋转样式状态,没有和索引绑定,修改一个状态所有面板都会生效
  • 命名逻辑混乱:useState返回的第一个值是状态本身,第二个是修改函数,你将状态值命名为setActive极易引发逻辑判断错误
  • 所有内容面板共用同一个ref,只能获取到最后一个面板的DOM属性,无法为每个面板计算独立高度

修复方案

仅保留「当前激活索引」这一个核心状态,所有面板的激活状态、样式、高度都通过循环索引和激活索引的对比动态生成,完全适配无唯一ID只用索引的场景。

修复后完整代码

import { useState, useRef } from "react";

const Accordion = (props) => {
  // 存储当前激活的索引,-1代表所有面板都关闭,需要默认打开第一个可改为0
  const [activeIndex, setActiveIndex] = useState(-1);
  // 用数组存储每个内容面板的ref
  const contentRefs = useRef([]);

  const toggleAccordion = (index) => {
    // 如果点击的是当前激活的面板则关闭,否则切换为点击的面板
    setActiveIndex(activeIndex === index ? -1 : index);
  };

  return (
    <div>
      {/* 若data为内部定义变量可替换为你自己的data变量 */}
      {props.data.map((item, index) => (
        <div key={index} className="accordion__section">
          <button
            className={`accordion ${activeIndex === index ? "active" : ""}`}
            onClick={() => toggleAccordion(index)}
          >
            <p className="accordion__title">{item.title}</p>
            <Chevron 
              className={`accordion__icon ${activeIndex === index ? "rotate" : ""}`} 
              width={10} 
              fill={"#777"} 
            />
          </button>
          <div
            ref={(el) => (contentRefs.current[index] = el)}
            style={{ 
              maxHeight: `${activeIndex === index ? contentRefs.current[index]?.scrollHeight + 'px' : '0px'}` 
            }}
            className="accordion__content"
          >
            <div>{item.content}</div>
          </div>
        </div>
      ))}
    </div>
  );
};

关键修改说明

  • 移除了冗余的高度、旋转样式状态,所有样式通过索引对比动态计算,天然和对应面板绑定
  • 用ref数组存储每个内容面板的DOM引用,切换时可以精准获取对应面板的滚动高度实现平滑动画
  • 切换逻辑仅修改激活索引值,所有面板自动根据索引匹配状态,不会出现同步切换的问题

内容的提问来源于stack exchange,提问作者Michael Morgan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 00:45:04