使用 React/TS 个功能组件一次切​​换一个列表项

Toggle one list item at a time with React/TS functional components

我有一个简单的组件,其中包含一些 mark-up:

的嵌套位
    import React, { ReactElement } from "react";

    type MenuItem = {
        title: string;
        subItems?: Array<string>;
    };

    type MenuConfig = Array<MenuItem>;

    function Item({ item }: { item: MenuItem }): ReactElement {
        const [showItem, setShowItem] = React.useState(false);
        const handleShowItem = (): void => {
            setShowItem(!showItem);
        };
        return (
            <>
                {item.subItems && (
                    <button onClick={() => handleShowItem()}>
                        {showItem ? "Hide" : "Expand"}
                    </button>
                )}
                {showItem && <SubItem item={item} />}
            </>
        );
    }

    function SubItem({ item }: { item: MenuItem }): ReactElement {
        const { title } = item;
        return (
            <ul>
                {item?.subItems?.map((subitem: string, i: number) => (
                    <li key={i}>
                        {subitem}
                    </li>
                ))}
            </ul>
        );
    }

    function Solution({ menuConfig }: { menuConfig: MenuConfig }): ReactElement {
        return (
            <>
                {menuConfig.map((item: MenuItem, i: number) => (
                    <div key={i}>
                        <span>{item.title}</span>
                        <Item item={item} />
                    </div>
                ))}
            </>
        );
    }

    export default Solution;

这是我传递的内容:

menuConfig={[
                {
                    title: "About",
                },
                {
                    title: "Prices",
                    subItems: ["Hosting", "Services"],
                },
                {
                    title: "Contact",
                    subItems: ["Email", "Mobile"],
                },
            ]}

现在,它按预期运行,如果项目包含 subItems,则会显示一个 Expand 按钮,如果单击该按钮,只会展开相关列表。

根据我的实施,我应该如何确保一次只打开一个列表

因此,如果用户单击 Expand 按钮,其他先前展开的列表应该关闭。

我不能弄乱传入的数据,因此无法将 ID 添加到 object,但标题是唯一的。

我已经搜索过了,虽然有一些例子,但它们对我没有帮助,我就是无法理解这个问题。

这是 React 上下文的完美用例。您本质上想要在菜单之间共享状态。您可以通过道具钻孔来实现这一点,但是上下文是一个更简洁的解决方案。

Code sandbox

const MenuContext = createContext<{
  expandedState?: [number, React.Dispatch<React.SetStateAction<number>>];
}>({});
function Solution(): ReactElement {
  const expandedState = useState<number>(null);
  const value = { expandedState };
  return (
    <>
      <MenuContext.Provider value={value}>
        {menuConfig.map((item: MenuItem, i: number) => (
          <div key={i}>
            <span>{item.title}</span>
            <Item i={i} item={item} />
          </div>
        ))}
      </MenuContext.Provider>
    </>
  );
}
function Item({ item, i }: { item: MenuItem; i: number }): ReactElement {
  const [expanded, setExpanded] = useContext(MenuContext)?.expandedState ?? [];
  const shown = expanded === i;
  return (
    <>
      {item.subItems && (
        <button onClick={() => setExpanded?.(i)}>
          {shown ? "Hide" : "Expand"}
        </button>
      )}
      {shown && <SubItem item={item} />}
    </>
  );
}