React单State控制子菜单:实现点击仅展开对应子菜单
问题:React导航菜单点击后仅展开当前项的子菜单
当前使用单个布尔值状态ShowSubMenu控制所有子菜单的展开/收起,导致点击任意一项时所有子菜单都会同步展开或收起。需求是点击某一项时仅展开对应的子菜单,且不想为每个导航项单独声明useState。
导航数据如下:
const navigation = [ { name: "Services", description: "Our services", href: "#", subMenu: [ { name: "Management" }, { name: "Development" }, { name: "Specialists" }, ], }, { name: "Experts", description: "our experts", href: "#", subMenu: [ { name: "Engineers" }, { name: "Project managers" }, { name: "Developers" }, { name: "Cloud solutions" }, ], }, ];
解决方案
核心思路是将状态从布尔值改为记录当前展开项的唯一标识(比如每个导航项的description,它是子菜单标题且唯一),通过判断当前项的标识是否与状态值匹配来控制子菜单的显示/隐藏。
修改后的代码:
- 调整状态定义:
// 用null表示初始无展开项,状态值存储当前展开项的description(或其他唯一字段) const [expandedKey, setExpandedKey] = useState(null);
- 渲染部分修改:
{navigation.map((item) => ( <> <div onClick={() => { // 点击时切换:如果当前项已展开则关闭,否则展开该项 setExpandedKey(expandedKey === item.description ? null : item.description); }} className="border-b-2 justify-between pb-4 pl-2 font-bold flex" > <h3 className="text-roboto">{item.description}</h3> <div className="border-solid border-b-2"></div> <ChevronDownIcon // 仅当前展开项的图标旋转 className={expandedKey === item.description ? "rotate-90 h-5 w-5" : "h-5 w-5"} /> </div> <div className="flex flex-col"> {item.subMenu.map((sm) => ( <div key={sm.name} // 仅当前展开项的子菜单显示 className={expandedKey !== item.description ? "hidden" : "pl-2 pt-2"} > {sm.name} </div> ))} </div> </> ))}
说明:
- 状态
expandedKey存储当前展开项的唯一标识(这里用description,也可以用name或其他不会重复的字段) - 点击导航项时,判断当前项的标识是否等于
expandedKey:如果相等则设置为null(关闭),否则设置为当前项的标识(展开) - 子菜单和图标的显示逻辑均基于
expandedKey与当前项标识的匹配关系,实现仅展开点击项的效果
内容的提问来源于stack exchange,提问作者Tihi
相关产品推荐
相关产品推荐

