React中点击其他子菜单时自动关闭已展开子菜单的实现问题
实现菜单互斥展开的解决方案
你当前的实现中每个MenuItem独立维护自身的展开状态,组件之间没有状态同步,所以无法实现点击一个菜单自动关闭其他已展开菜单的效果。我们可以通过状态提升的方式,把展开状态统一放到父组件Menu中管理,具体修改如下:
1. 修改Menu.js代码
将展开状态的控制权移到父组件,统一管理当前激活的展开项:
import React, { useState } from 'react' import MenuItem from '../MenuItem'; import { SidebarData } from '../../helpers/SidebarData'; import * as C from './styles'; const Menu = () => { // 存储当前展开的菜单项唯一标识,默认无展开项设为null const [activeMenuId, setActiveMenuId] = useState(null); const handleMenuToggle = (menuId) => { // 点击已展开的菜单则关闭,否则切换为当前点击的菜单 setActiveMenuId(activeMenuId === menuId ? null : menuId) } return ( <C.Container> <C.MenuArea> {SidebarData.map((item, index) => { // 若SidebarData的项有唯一id优先用item.id,无则先用index作为临时标识 const menuId = item.id || index; return <MenuItem item={item} key={menuId} isOpened={activeMenuId === menuId} onToggle={() => handleMenuToggle(menuId)} />; })} </C.MenuArea> </C.Container> ) }; export default Menu
2. 修改MenuItem.js代码
移除内部的独立展开状态,改用父组件传入的状态和回调:
import React from 'react'; import { NavLink } from 'react-router-dom'; import * as C from './styles'; const MenuItem = ({ item, isOpened, onToggle }) => { return ( <C.NavUnlisted> <NavLink to={item.path} onClick={item.subNav ? onToggle : undefined} activeClassName='current' exact={item.path === '/'} > <C.SidebarLink> <div> {item.icon} <C.SidebarLabel>{item.title}</C.SidebarLabel> </div> <div> {item.subNav && isOpened ? item.iconOpened : item.subNav ? item.iconClosed : null} </div> </C.SidebarLink> </NavLink> {isOpened && item.subNav.map((subItem, index) => { return ( <NavLink to={subItem.path} key={index} activeClassName='current' > <C.DropdownLink> {subItem.icon} <C.SidebarLabel>{subItem.title}</C.SidebarLabel> </C.DropdownLink> </NavLink> ); })} </C.NavUnlisted> ); }; export default MenuItem;
提示:如果你的SidebarData配置项中已经存在唯一标识字段(比如id),建议替换掉示例中用index作为menuId的写法,避免数组顺序变化导致的状态异常。
内容的提问来源于stack exchange,提问作者BraulioPortela
相关产品推荐
相关产品推荐

