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

React开发问题:如何自动打开新添加的手风琴(accordion)组件项?

问题根因
  • React的状态更新是异步批量执行的,你调用setFaqs(newFaq)之后,当前作用域内的faqs还是更新前的旧数组,此时读取faqs.length拿到的是新增前的数组长度,自然无法匹配到新插入项的索引
  • 状态类型不匹配:你初始化clicked为字符串"0",但循环渲染时的index是数字类型,用全等===判断时,数字和字符串永远不相等,也会导致开合状态判断异常
修复方案

1. 修正Accordion.jsx逻辑

首先统一clicked状态的类型为数字,再直接用构建完成的新数组计算新项索引,避免读取旧状态:

import AccordionItem from "./AccordionItem";
import { useState } from "react";

export default function Accordion() {
  const initialFaqs = [
    {
      question: "Lorem ipsum dolor sit amet?",
      answer:
        "Tenetur ullam rerum ad iusto possimus sequi mollitia dolore sunt quam praesentium. Tenetur ullam rerum ad iusto possimus sequi mollitia dolore sunt quam praesentium.Tenetur ullam rerum ad iusto possimus sequi mollitia dolore sunt quam praesentium."
    },
    {
      question: "Dignissimos sequi architecto?",
      answer:
        "Aperiam ab atque incidunt dolores ullam est, earum ipsa recusandae velit cumque. Aperiam ab atque incidunt dolores ullam est, earum ipsa recusandae velit cumque."
    },
    {
      question: "Voluptas praesentium facere?",
      answer:
        "Blanditiis aliquid adipisci quisquam reiciendis voluptates itaque."
    }
  ];

  const [faqs, setFaqs] = useState(initialFaqs);
  // 初始值改为数字类型,无展开项时设为null更合理
  const [clicked, setClicked] = useState(0);

  const handleToggle = (index) => {
    if (clicked === index) {
      return setClicked(null);
    }
    setClicked(index);
  };

  const addFaq = () => {
    const newFaq = [...faqs];
    // 直接用新数组计算新增项的索引,不要用旧的faqs状态
    const newItemIndex = newFaq.length;
    newFaq.push({
      question: "This accordion item should automatically open",
      answer:
        "Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur."
    });
    setFaqs(newFaq);
    setClicked(newItemIndex);
  };

  return (
    <div>
      <ul className="accordion">
        {faqs.map((faq, index) => (
          <AccordionItem
            onToggle={() => handleToggle(index)}
            active={clicked === index}
            key={index}
            faq={faq}
          />
        ))}
      </ul>
      <button onClick={addFaq} className="add-faq-btn">
        添加问题
      </button>
    </div>
  );
}

2. 优化AccordionItem.jsx避免初始渲染报错

新增项首次渲染时ref可能还未挂载,直接读取contentEl.current会抛出空值错误,用useEffect监听active状态动态修改高度即可:

import { useRef, useEffect } from "react";

export default function AccordionItem({ faq, active, onToggle }) {
  const contentEl = useRef();

  // 监听active状态动态设置高度,避免初始空ref报错
  useEffect(() => {
    if (!contentEl.current) return;
    contentEl.current.style.height = active ? `${contentEl.current.scrollHeight}px` : "0px";
  }, [active]);

  const { question, answer } = faq;
  return (
    <li className={`accordion_item ${active ? "active" : ""}`}>
      <button className="button" onClick={onToggle}>
        {question}
        <span className="control">{active ? "—" : "+"} </span>
      </button>
      <div
        ref={contentEl}
        className="answer_wrapper"
      >
        <div className="answer">{answer}</div>
      </div>
    </li>
  );
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 13:15:02