ReactJS 功能组件:手风琴,允许使用 useState 多选打开

ReactJS Function Component: accordion, allow for multiple selected open with useState

我在 ReactJS 中模拟了手风琴可折叠面板的简单逻辑。我正在尝试允许打开多个可折叠项,但无论单击哪个可折叠项,我都无法避免同时打开和关闭所有可折叠项。下面是手风琴一次只允许折叠一个的逻辑。

//Accordion.js
import React, { useState } from "react";
import styled, { css } from "styled-components";
import PropTypes from "prop-types";
import Collapse from "./Collapse";
import Header from "./Header";
const Accordion = ({ list, icon}) => {
  const [isActiveIndex, setActiveIndex] = useState(null);
  const toggleItem = index => {
    setActiveIndex(isActiveIndex === index ? null : index);
  };
  return (
    <Wrapper>
      {list.map((item, index) => {
        const checkOpen = isActiveIndex === index;

        return (
          <Container key={index}>
            <Header
              title={item.title}
              icon={icon}
              id={index}
              onClick={toggleItem}
            />
            <Body isOpen={checkOpen}>
              <Collapse isOpen={checkOpen}>{item.content}</Collapse>
            </Body>
          </Container>
        );
      })}
    </Wrapper>
  );
};

我在此处的 CodeSandBox 中创建了整个模拟:https://codesandbox.io/s/1r2mvk87q

对于初始手风琴,我正在使用 useState 并检查活动索引 - 对于 allow multiple 我想我应该检查被点击项目的先前状态,但我无法通过单击项目作为要检查状态的唯一目标。

//AccordionMultiple.js
const AccordionM = ({ list, icon }) => {
  const [isOpen, setOpen] = useState(false);
  const toggleItemM = index => {
    setOpen(prevState => !prevState);
  };

  return (
    <Wrapper>
      {list.map((item, index) => {
        return (
          <Container key={index}>
            <Header
              title={item.title}
              icon={icon}
              id={index}
              onClick={toggleItemM}
            />
            <Body isOpen={isOpen}>
              <Collapse isOpen={isOpen}>{item.content}</Collapse>
            </Body>
          </Container>
        );
      })}
    </Wrapper>
  );
};

为了允许多个可折叠列,您可以使用对象而不是单个索引

const Accordion = ({ list, icon}) => {
  const [isActivePanel, setActivePanel] = useState({});
  const toggleItem = index => {
    setActivePanel(prevState => ({...prevState, [index]: !Boolean(prevState[index])}));
  };
  return (
    <Wrapper>
      {list.map((item, index) => {
        const checkOpen = isActivePanel[index];

        return (
          <Container key={index}>
            <Header
              title={item.title}
              icon={icon}
              id={index}
              onClick={toggleItem}
            />
            <Body isOpen={checkOpen}>
              <Collapse isOpen={checkOpen}>{item.content}</Collapse>
            </Body>
          </Container>
        );
      })}
    </Wrapper>
  );
};