如何实现React下拉菜单点击时仅展开当前菜单不全部打开
问题现象
实现React下拉菜单组件时出现异常:点击任意单个主菜单尝试展开对应子菜单时,所有主菜单的子菜单会被同时展开。
原问题实现代码如下:
import React from "react"; export default function App() { const [active, setActive] = React.useState(false); function handleClick() { setActive(!active); } const text = [ { id: 1, name: "Hello", subText: [ { id: 1, name: "Sub Hello" } ] }, { id: 2, name: "Bye", subText: [ { id: 2, name: "Sub Bye" } ] } ]; return ( <div style={{ backgroundColor: "gray", padding: 4 }}> {text?.map(({ name, id, subText }) => ( <div style={{ display: "flex", alignItems: "center" }}> <ul style={{ width: 100 }}> <li style={{ cursor: "pointer" }} onClick={handleClick}> {name} </li> </ul> <div> {active && subText?.map(({ name, id }) => ( <ul key={id}> <li>{name}</li> </ul> ))} </div> </div> ))} </div> ); }
根因分析
- 所有菜单项共用同一个布尔类型的
active状态,没有区分当前激活的是哪个菜单项 - 遍历渲染所有菜单项时,只要
active值为true,所有菜单项的子菜单判断条件都会命中,因此全部展开 - 点击事件没有传入当前点击菜单项的唯一标识,无法定位要操作的具体菜单
- 列表遍历缺失必填的
key属性,存在渲染性能和状态错位隐患
修复方案
将布尔状态替换为存储当前激活菜单ID的状态,点击时传入对应菜单ID,渲染子菜单时仅当当前菜单ID与激活ID一致时才展示内容:
import React from "react"; export default function App() { // 存储当前激活的菜单id,默认值为null表示无激活菜单 const [activeId, setActiveId] = React.useState(null); // 点击时传入当前菜单id,支持点击已展开菜单时收起 function handleClick(menuId) { setActiveId(prev => prev === menuId ? null : menuId); } const text = [ { id: 1, name: "Hello", subText: [ { id: 1, name: "Sub Hello" } ] }, { id: 2, name: "Bye", subText: [ { id: 2, name: "Sub Bye" } ] } ]; return ( <div style={{ backgroundColor: "gray", padding: 4 }}> {text?.map(({ name, id, subText }) => ( <div key={id} style={{ display: "flex", alignItems: "center" }}> <ul style={{ width: 100 }}> <li style={{ cursor: "pointer" }} onClick={() => handleClick(id)} > {name} </li> </ul> <div> {/* 仅匹配当前激活id的菜单渲染子内容 */} {activeId === id && subText?.map(({ name, id: subId }) => ( <ul key={subId}> <li>{name}</li> </ul> ))} </div> </div> ))} </div> ); }
内容的提问来源于stack exchange,提问作者Athief Aleaf
相关产品推荐
相关产品推荐

