React侧边栏菜单未按权限更新,仅热构建后生效问题排查
问题排查与修复方案
核心问题分析
顶层await语法错误
你在data.jsx的对象字面量中直接使用await keycloakService.hasRole(...),这是非法语法——await只能在异步函数内部使用,导致visibility实际是一个未resolved的Promise对象,而非预期的'true'/'false'字符串。初始渲染时,itemData.visibility == 'true'的判断永远不成立,只有热更新时权限请求已完成,这个Promise被隐式处理后才会显示正确结果。静态数组无法响应异步权限结果
SIDEBAR_DATA是静态常量,初始化时keycloakService.hasRole的异步请求还未返回结果,因此visibility的初始值错误,无法动态更新视图。数据引用不匹配
SidebarItems.jsx中导入的是dummyData,但data.jsx导出的是SIDEBAR_DATA,这会导致渲染的不是你配置了权限的目标菜单数据。
修复代码
1. 重构data.jsx:定义基础菜单结构,剥离权限逻辑
import AdminPanelSettingsOutlined from "@mui/icons-material/AdminPanelSettingsOutlined"; import { HomeIcon, LayoutIcon, CalendarIcon, InvoiceIcon, UserIcon, RolesIcon, PagesIcon, AuthIcon, WizardIcon, ModalIcon, } from "./Icons"; // 基础菜单数据,仅定义结构和权限要求,不做权限判断 export const BASE_SIDEBAR_DATA = [ { id: 1, name: "Home", path: "/secured", icon: <HomeIcon/>, requiredRoles: [] // 无权限要求的菜单留空数组 }, { id: 2, name: "Administration", path: "/Administration", icon: <AdminPanelSettingsOutlined/>, requiredRoles: ['NexaAdmin'] // 指定需要的角色 }, ];
2. 修改SidebarItems.jsx:异步获取权限,动态生成可显示菜单
import React, { useState, useEffect } from "react"; import { Link } from "react-router-dom"; import { ItemsList, ItemContainer, ItemWrapper, ItemName, } from "./SidebarStyles"; import { BASE_SIDEBAR_DATA } from "./data"; // 导入基础菜单数据 import keycloakService from "../KeycloakService"; const SidebarItems = ({ displaySidebar }) => { const [activeItem, setActiveItem] = useState(0); const [visibleMenuItems, setVisibleMenuItems] = useState([]); useEffect(() => { // 异步获取权限,过滤可显示菜单 const fetchVisibleMenus = async () => { const visibleItems = await Promise.all( BASE_SIDEBAR_DATA.map(async (item) => { // 无权限要求的直接显示,否则检查角色 if (item.requiredRoles.length === 0) { return item; } const hasPermission = await keycloakService.hasRole(item.requiredRoles); return hasPermission ? item : null; }) ); // 过滤掉无权限的菜单 setVisibleMenuItems(visibleItems.filter(Boolean)); }; fetchVisibleMenus(); // 监听keycloak状态变化,用户身份变更时自动更新菜单 const keycloakListener = keycloakService.onAuthStateChanged(() => { fetchVisibleMenus(); }); return () => keycloakListener?.unsubscribe(); }, []); return ( <ItemsList> {visibleMenuItems.map((itemData) => ( <ItemContainer key={itemData.id} onClick={() => setActiveItem(itemData.id)} className={itemData.id === activeItem ? "active" : ""} > <Link to={itemData.path}> <ItemWrapper> {itemData.icon} <ItemName displaySidebar={displaySidebar}> {itemData.name} </ItemName> </ItemWrapper> </Link> </ItemContainer> ))} </ItemsList> ); }; export default SidebarItems;
关键修复点说明
- 把权限判断从静态数组移到组件的
useEffect中,利用异步函数正确获取keycloak权限结果 - 通过
useState维护可显示菜单列表,权限结果返回后自动触发视图更新 - 增加keycloak状态监听,确保用户登录/登出或角色变更时,菜单权限能同步更新
- 修正了数据引用错误,确保使用正确的基础菜单数据
内容的提问来源于stack exchange,提问作者user3509208
相关产品推荐
相关产品推荐

