React中如何实现点击打开一个菜单时自动关闭其他已展开菜单
解决方案
问题根因
展开状态分散在每个MenuCard组件内部独立维护,组件之间状态不互通,无法实现点击一个菜单时同步关闭其他菜单的互斥逻辑。之前为每个菜单单独声明多个useState的方案也不可行,因为每个组件实例的状态都是独立的,修改当前组件的状态无法影响其他组件。
改造步骤
1. 改造父组件 Dashboard.tsx
将展开状态提升到父组件统一管理,新增activeMenu状态存储当前展开的菜单唯一标识(这里直接用菜单title即可,也可以新增独立id字段),并将状态和修改方法通过props传递给子组件:
// Dashboard.tsx // 新增激活菜单状态 const [activeMenu, setActiveMenu] = React.useState<string | null>(null) setMenuList([ { title: "Thermal Comfort", icon: thermal, decorator: new ManekinDecorator(IModelApp.viewManager.selectedView!), tooltip: "Thermal Comfort", }, { title: "Surface Plots", icon: surfacePlot, decorator: null, tooltip: "Surface Plots", }, { title: "Contour Plots", icon: contour, decorator: null, tooltip: "Contour Plots", }, { title: "Comfort Cloud", icon: comfortCloud, decorator: new ComfortDecorator(), tooltip: "Comfort Cloud", }, { title: "Flowlines", icon: flowline, //decorator: getFlowLineDecorator(), decorator: null, tooltip: "FlowLines", }, ]); } else { setMenuList([]); setIsDropDownVisibal(false); } }, [viewPort]); <div className="menu"> <div style={{ overflowY: "scroll", width: "inherit" }}> {menuList.map((menu) => ( <MenuCard key={menu.title} menu={menu.title} icon={menu.icon} decorator={menu.decorator} tooltip={menu.tooltip} // 新增两个props传递给子组件 activeMenu={activeMenu} setActiveMenu={setActiveMenu} /> ))} </div> </div>
2. 改造子组件 MenuCard.tsx
删除内部维护的所有展开相关状态,直接通过父组件传递的activeMenu判断当前菜单是否需要展开:
// MenuCard.tsx const MenuCard = (props: any) => { const [toggle, setToggle] = React.useState(true); const { menu, icon, tooltip, activeMenu, setActiveMenu } = props; const onClick = () => { // 互斥展开逻辑:点击的菜单和当前激活的一致就收起,否则设为当前激活菜单 setActiveMenu(activeMenu === menu ? null : menu) // 原有decorator逻辑保持不变 if (props.decorator !== null) { if (toggle) { IModelApp.viewManager.decorators.forEach((decorator) => { IModelApp.viewManager.dropDecorator(decorator); }); IModelApp.viewManager.addDecorator(props.decorator); } else IModelApp.viewManager.dropDecorator(props.decorator); } setToggle(!toggle); }; return ( <div> <div className="mainMenu" onClick={onClick}> <div className="icon"> <img src={icon} alt="icon" className="menuIcon" /> </div> <div className="menuTitle"> <p className="title">{menu}</p> </div> <InfoTooltip tooltipText={tooltip} /> </div> {/* 直接通过父组件传的activeMenu判断是否展开当前菜单 */} {activeMenu === menu && ( <GetExpandedMenu menuName={menu} decorator={props.decorator} /> )} </div> ); }; export default MenuCard;
优化说明
如果不需要支持点击当前展开的菜单收起,只需要把setActiveMenu(activeMenu === menu ? null : menu)修改为setActiveMenu(menu)即可。GetExpandedMenu组件无需做任何修改即可正常运行。
内容的提问来源于stack exchange,提问作者Nishtha Sharma
相关产品推荐
相关产品推荐

