You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 02:36:08