【问题标题】:How can I toggle accordion panels individually using React Hooks?如何使用 React Hooks 单独切换手风琴面板?
【发布时间】:2021-12-13 08:34:06
【问题描述】:

目前,所有手风琴面板都在同时切换。我试过将索引传递给点击处理程序,但没有运气。如何将当前索引与当前 setActive 变量进行比较以单独打开和关闭手风琴面板?我在生产中使用的数据没有唯一的 id,这就是我使用 index.html 的原因。感谢您的任何建议!

演示:https://codesandbox.io/s/react-accordion-using-react-hooks-forked-fup4w?file=/components/Accordion.js:141-1323

const Accordion = (props) => {
  const [setActive, setActiveState] = useState(0);
  const [setHeight, setHeightState] = useState("0px");
  const [setRotate, setRotateState] = useState("accordion__icon");

  const content = useRef(null);

  const toggleAccordion = (index) => {
    setActiveState(setActive === index ? "active" : "");
    setHeightState(
      setActive === "active" ? "0px" : `${content.current.scrollHeight}px`
    );
    setRotateState(
      setActive === "active" ? "accordion__icon" : "accordion__icon rotate"
    );
  }

  return (
    <div>
      {data.map((item, index) => (
        <div key={index} className="accordion__section">
          <button
            className={`accordion ${setActive}`}
            onClick={() => toggleAccordion(index)}
          >
            <p className="accordion__title">{item.title}</p>
            <Chevron className={`${setRotate}`} width={10} fill={"#777"} />
          </button>
        <div
          ref={content}
          style={{ maxHeight: `${setHeight}` }}
          className="accordion__content"
        >
          <div>{item.content}</div>
       </div>
    </div>
    ))}
  </div>
  );
};

【问题讨论】:

    标签: reactjs react-hooks accordion


    【解决方案1】:

    您的代码中的问题是您正在生成一个通用的 setActive 状态,然后将其传递给您的地图函数中的所有项目。您必须更改状态管理才能找到每个项目是否处于活动状态。 我会修改你的组件:

    const Accordion = (props) => {
    
      const [activeIndex, setActiveIndex] = useState(0);
    
      const content = useRef(null);
        
      return (
        <div>
          {data.map((item, index) => {
             const isActive = index === activeIndex
            return (
            <div key={index} className="accordion__section">
              <button
                className={`accordion ${isActive ? "active" : ""}`}
                onClick={() => setActiveIndex(index)}>
                <p className="accordion__title">{item.title}</p>
                <Chevron className={`${isActive ? "accordion__icon" : "accordion__icon rotate" }`} width={10} fill={"#777"} />
              </button>
            <div
              ref={content}
              style={{ maxHeight: `${isActive ? "0px" : `${content.current.scrollHeight}px`}` }}
              className="accordion__content">
              <div>{item.content}</div>
           </div>
        </div>
        )})}
      </div>
      );
    };
    

    这个想法是,对于循环中的每个项目,您可以找到哪个 on 处于活动状态,然后根据此分配类/样式。可以进行更多重构,但现在我让你清理一下,因为这个想法应该存在:)

    【讨论】:

    • 感谢您的帮助!这绝对是正确的想法。我收到一个错误 TypeError: Cannot read property 'scrollHeight' of null
    • 问题是您在元素的映射(循环)中分配了一个应该是唯一的 ref,因此每个元素都将自己分配给 ref 并且无法正常工作:) .我邀请您检查这个问题,该问题可能应该解决它并且与您的第一个问题没有直接关系:stackoverflow.com/questions/52448143/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-13
    • 1970-01-01
    • 2016-04-04
    相关资源
    最近更新 更多