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

如何在数组映射中为Material-Tailwind菜单创建动态useState控制子菜单

解决Material-Tailwind多子菜单展开状态独立控制问题

当前代码中所有子菜单共用同一个menuOpen状态,导致点击任意一个菜单时,所有子菜单会同步展开/收起。要实现每个子菜单独立控制,需将状态改为记录单个菜单的展开状态,具体实现如下:

核心修改点

  • 将单个布尔值状态改为对象,用菜单标题作为唯一key存储对应展开状态
  • 为每个菜单单独编写展开/收起的切换逻辑
  • 修正移动端状态的独立控制问题,避免移动端菜单状态冲突

修改后的完整代码

import { useState } from "react";
import { Menu, MenuHandler, MenuList, MenuItem, ListItem, Typography } from "@material-tailwind/react";
import { ChevronDownIcon } from "@heroicons/react/24/outline";

const menus = [
  {
    title: "About",
    submenu: [
      { subtitle: "Submenu 1-1" },
      { subtitle: "Submenu 1-2" },
    ],
  },
  {
    title: "Contact Us",
    submenu: [
      { subtitle: "Submenu 2-1" },
      { subtitle: "Submenu 2-2" },
    ],
  },
];

function NavList() {
  // 用对象存储桌面端每个菜单的展开状态,key为菜单title
  const [desktopMenuStates, setDesktopMenuStates] = useState({});
  // 用对象存储移动端每个菜单的展开状态
  const [mobileMenuStates, setMobileMenuStates] = useState({});

  // 切换桌面端指定菜单的展开状态
  const toggleDesktopMenu = (menuTitle) => {
    setDesktopMenuStates(prev => ({
      ...prev,
      [menuTitle]: !prev[menuTitle]
    }));
  };

  // 切换移动端指定菜单的展开状态
  const toggleMobileMenu = (menuTitle) => {
    setMobileMenuStates(prev => ({
      ...prev,
      [menuTitle]: !prev[menuTitle]
    }));
  };

  return (
    <>
      {menus.map((menu, key) => (
        <React.Fragment key={key}>
          {menu.submenu ? (
            <>
              <Menu
                open={desktopMenuStates[menu.title] || false}
                handler={() => toggleDesktopMenu(menu.title)}
                allowHover={true}
              >
                <MenuHandler>
                  <Typography as="div">
                    <ListItem
                      selected={desktopMenuStates[menu.title] || false}
                      onClick={() => toggleMobileMenu(menu.title)}
                    >
                      {menu.title}
                      {/* 桌面端下拉图标 */}
                      <ChevronDownIcon
                        strokeWidth={2.5}
                        className={`hidden h-4 w-4 transition-transform lg:block ${desktopMenuStates[menu.title] ? "rotate-180" : ""}`}
                      />
                      {/* 移动端下拉图标 */}
                      <ChevronDownIcon
                        strokeWidth={2.5}
                        className={`block h-3 w-3 transition-transform lg:hidden ${mobileMenuStates[menu.title] ? "rotate-180" : ""}`}
                      />
                    </ListItem>
                  </Typography>
                </MenuHandler>
                <MenuList className="hidden min-w-fit rounded-xl p-2 px-4 lg:block">
                  <ul className="flex flex-col gap-y-2 outline-none outline-0">
                    {menu.submenu.map((subItem, subKey) => (
                      <a href="#" key={subKey}>
                        <MenuItem className="items-center rounded-lg p-0">
                          <div>
                            <Typography
                              variant="h6"
                              className="font-medium text-light-blue"
                            >
                              {subItem.subtitle}
                            </Typography>
                          </div>
                        </MenuItem>
                      </a>
                    ))}
                  </ul>
                </MenuList>
              </Menu>
            </>
          ) : (
            <Typography as="a" href="#">
              <ListItem className="flex items-center gap-1 py-2 pr-4">
                {menu.title}
              </ListItem>
            </Typography>
          )}
        </React.Fragment>
      ))}
    </>
  );
}

export default NavList;

关键说明

  1. 状态隔离:通过desktopMenuStates和mobileMenuStates两个对象,分别存储桌面端、移动端每个菜单的独立状态,避免不同菜单间的状态干扰。
  2. 精准切换:切换函数通过菜单标题作为唯一标识,仅更新对应菜单的状态,不会影响其他菜单。
  3. 变量修正:原代码中map循环里的变量名错误(item应为menu)已统一修正,避免逻辑混淆。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 01:52:11