React下拉菜单点击菜单项时如何隐藏其他项仅显示当前子菜单
问题根因
当前实现中每个ItemsMenu组件独立维护自身的子菜单展开状态,组件之间状态完全隔离,点击新菜单项时无法触发其他菜单项的状态更新,因此会出现多个子菜单同时展开的问题。这种分散式状态管理也没法直接指定索引修改对应菜单项的展开状态。
修复思路
将子菜单的展开状态提升到父组件Navigationn统一管理,父组件只需要维护一个「当前激活展开的菜单项索引」状态即可:
- 状态值为
null时,所有子菜单全部收起 - 状态值为某一菜单项的索引时,仅对应该索引的菜单项渲染子菜单
- 点击菜单项时更新该状态值,即可自动实现「展开新菜单时自动收起其他已展开菜单」的效果,不需要手动逐个修改其他菜单项的状态
修正后完整代码
父组件 Navigationn
const Navigationn = ({displayHandlerMenu}) =>{ // 统一维护当前展开的菜单项索引,默认无展开项 const [activeSubmenuIndex, setActiveSubmenuIndex] = useState(null); const handleMenuToggle = (clickIndex) => { // 点击已展开的菜单则收起,否则展开当前点击项、其余自动收起 setActiveSubmenuIndex(activeSubmenuIndex === clickIndex ? null : clickIndex); }; return ( <> <SidebarWrap> {menuItems.map((item, index) => ( <ItemsMenu key={index} item={item} index={index} isSubmenuOpen={activeSubmenuIndex === index} onMenuToggle={handleMenuToggle} displayHandlerMenu={displayHandlerMenu} /> ))} </SidebarWrap> </> ); }; export default Navigationn;
子组件 ItemsMenu
移除组件内部独立维护的submenu状态,完全通过父组件传入的props控制展开逻辑:
const ItemsMenu = ({ item, displayHandlerMenu, index, isSubmenuOpen, onMenuToggle }) =>{ return ( <> <MenuItemLink to={item.path} onClick={() => onMenuToggle(index)}> <MenuItem>{item.title}</MenuItem> </MenuItemLink> {item.submenu && isSubmenuOpen && item.submenu.map((subItem, subIndex) => ( <ItemsSubMenu key={subIndex} item={subItem} displayHandlerMenu={displayHandlerMenu} /> ))} </> ); }; export default ItemsMenu;
注意点
- 修复了原代码中嵌套
map时索引变量重名的问题,内层子菜单遍历使用subIndex作为索引,避免变量冲突 - 不需要手动遍历所有菜单项逐个设置展开状态为false,单一数据源更新后,所有子组件会自动根据传入的
isSubmenuOpen值重新渲染 - 默认支持点击已展开的菜单项收起子菜单,符合通用菜单交互习惯
内容的提问来源于stack exchange,提问作者KornelDev96
相关产品推荐
相关产品推荐

