React应用侧边栏无法展示完整菜单树 控制台报函数子元素警告
问题根因梳理
1. 三级菜单无法展示的原因
你当前的菜单渲染逻辑仅支持两级菜单结构,未对二级菜单的子模块做递归判断:
- SideBar.tsx中只对第一层module判断了
subModules?.length,决定渲染可展开项还是普通项 - 二级subModule(例如Admin项)本身也有subModules,但你直接把它传给
getSideBarItemFromModule转成了普通侧边栏项,没有判断它是否包含子模块,因此不会生成嵌套的可展开组件,自然看不到三级的Region/Country菜单
2. 函数作为React子元素的警告原因
你所有的title属性都来自labels对象的方法(代码里正常调用逻辑是module.title()),存在某个场景下你没有执行这个函数,直接把module.title(函数本身)当成值传给了React组件的children属性,最常见的就是工具方法里漏写括号、或者组件传参时没调用函数。
修复步骤
步骤1:改造为递归渲染逻辑,支持无限层级菜单
首先修改Sidebaritem.tsx的类型定义,让可展开项支持嵌套结构:
export interface ExpandableSidebarItemProps { title: string; icon?: ReactNode; collapsed: boolean; onExpand?: () => void; // 修改son类型,支持嵌套的可展开项或者普通项 son?: Array<SidebarItemProps | ExpandableSidebarItemProps>; }
调整ExpandableSidebarItem的渲染逻辑,判断子项类型对应渲染:
<Collapse in={!collapsed}> <List> {son.map((c, index) => { // 存在子项则渲染可展开组件 if ('son' in c && c.son?.length) { return <ExpandableSidebarItem key={index} {...c} /> } // 普通菜单项渲染 return ( <RouterLink key={index} className={classes.link} to={c.href}> <ListItem className={classes.nestedItem} button selected={c.selected} onClick={c.onListItemClick}> <ListItemText primary={c.title} /> </ListItem> </RouterLink> ) })} </List> </Collapse>
在SideBar.tsx中新增递归生成菜单项的方法,替换原来的单层map逻辑:
const getSideBarConfigFromModule = (module: Module): SidebarItemProps | ExpandableSidebarItemProps => { if (module.subModules?.length) { return { title: module.title(), collapsed: module.collapsed ?? false, onExpand: () => module.collapsed ? dispatch(expandModule(module.key)) : dispatch(collapseModule(module.key)), son: module.subModules.map(subMod => getSideBarConfigFromModule(subMod)) } } return getSideBarItemFromModule(module) }
最后把drawerContent里的modules.map替换为调用上面的方法即可。
步骤2:修复函数类型警告
检查所有使用title的场景,确保都执行了函数拿到字符串值:
比如你原来的getViewFromModule方法里存的是函数本身,修改为:
const getViewFromModule = (module: Module): View => ({ key: module.key, path: module.path, title: module.title(), // 调用函数拿到字符串值 cleanStateAction: module.cleanStateAction });
同时检查SidebarSection组件的传参,确保是module.section()而不是module.section。
步骤3:补充modules.ts的递归查找逻辑
你原来的getKeyFromPath、getModuleFromKey、getBreadCrumbs都只支持两级查找,需要改成递归遍历所有层级的subModules,否则三级菜单的路径匹配、面包屑展示都会异常,以getKeyFromPath为例:
export const getKeyFromPath = (path: string, moduleList: Module[] = modules): number => { for (const module of moduleList) { if (module.path === path) return module.key; if (module.subModules?.length) { const subKey = getKeyFromPath(path, module.subModules); if (subKey) return subKey; } } return 0; };
其余两个方法改成同逻辑的递归写法即可。
内容的提问来源于stack exchange,提问作者Manuel_dev
相关产品推荐
相关产品推荐

