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

React嵌套路由路径渲染异常及Admin权限控制问题求助

React嵌套路由与权限控制问题

问题描述

  • 点击侧边栏菜单时,路由地址能跳转到/{指定路由路径},但无法正确渲染对应页面组件
  • 需实现权限控制,仅允许admin角色访问特定标签页

相关代码

index.js

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import { Provider } from 'react-redux';
import { BrowserRouter, Route, Routes } from 'react-router-dom';
import { AuthProvider } from './context/AuthProvider';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
      <BrowserRouter>
        <AuthProvider>
          <Routes>
            <Route path="/*" element={ <App /> } />
          </Routes>
        </AuthProvider>
      </BrowserRouter>
  </React.StrictMode>
);

App.js

import React from "react";
import { Route, Routes } from "react-router-dom";
import Layout from "./Components/PublicPages/Layout";
import RequireAuth from "./Components/RequireAuth";
import Unauthorized from "./Components/PublicPages/Unauthorized";
import Missing from "./Components/PublicPages/Missing";
import Register from "./Components/PublicPages/Register";
import Login from "./Components/PublicPages/Login";
import Admin from "./Components/RolePages/Admin";
import AdminHome from "./Components/RolePages/AdminLayoutComponents/AdminHome";
import Complaints from "./Components/RolePages/AdminLayoutComponents/Complaints";

function App() {
  return (
    <React.Suspense fallback={<div>Loading</div>}>
      <Routes>
        <Route path="/register" element={<Register />} />
        {/* public routes */}
        <Route path="/login" element={<Login />} />
        <Route path="/unauthorized" element={<Unauthorized />} />
        <Route path="/" element={<Layout />}>
          {/* we want to protect these routes */}
          <Route element={<RequireAuth allowedPermissions="admin" />}>
            <Route index={true} element={<Admin />} />
            <Route path="/admin" element={<AdminHome />} />
            <Route path='/complaints' element={<Complaints />} />
          </Route>
          {/* catch all */}
        </Route>
        <Route path="*" element={<Missing />} />
      </Routes>
    </React.Suspense>
  );
}

export default App;

Admin.jsx

import * as React from "react";
import PropTypes from "prop-types";
import AppBar from "@mui/material/AppBar";
import Box from "@mui/material/Box";
import CssBaseline from "@mui/material/CssBaseline";
import Divider from "@mui/material/Divider";
import Drawer from "@mui/material/Drawer";
import IconButton from "@mui/material/IconButton";
import InboxIcon from "@mui/icons-material/MoveToInbox";
import List from "@mui/material/List";
import ListItem from "@mui/material/ListItem";
import ListItemButton from "@mui/material/ListItemButton";
import ListItemIcon from "@mui/material/ListItemIcon";
import ListItemText from "@mui/material/ListItemText";
import MailIcon from "@mui/icons-material/Mail";
import MenuIcon from "@mui/icons-material/Menu";
import Toolbar from "@mui/material/Toolbar";
import Typography from "@mui/material/Typography";
import { NavLink } from "react-router-dom";

const drawerWidth = 240;

function Admin(props) {
  const { window } = props;
  const [mobileOpen, setMobileOpen] = React.useState(false);
  const [isClosing, setIsClosing] = React.useState(false);

  const handleDrawerClose = () => {
    setIsClosing(true);
    setMobileOpen(false);
  };

  const handleDrawerTransitionEnd = () => {
    setIsClosing(false);
  };

  const handleDrawerToggle = () => {
    if (!isClosing) {
      setMobileOpen(!mobileOpen);
    }
  };
  
  const sidebarItems = [
    { title: "Admin Home", link: "/admin" },
    { title: "Complaints", link: "/complaints" },
    { title: "Account Opener Home", link: "/account-opener-home" },
    { title: "Bank Home", link: "/bank-home" },
    { title: "Higher Management Home", link: "/higher-management-home" },
    { title: "Manage Users", link: "/manage-users" },
    { title: "Logout", link: "/logout" },
  ];

  const drawer = (
    <div style={{ color: "#b8c7ce" }}>
      <Divider />
      <List>
        {sidebarItems.map((text, index) => (
          <ListItem disablePadding key={text}>
            <NavLink
              to={`/${text.link}`}
              style={{ textDecoration: "none", color: "inherit" }}
            >
              <ListItemButton>
                <ListItemText primary={text.title} />
              </ListItemButton>
            </NavLink>
          </ListItem>
        ))}
      </List>
      <Divider />
    </div>
  );

  return (
    <Box sx={{ display: "flex" }}>
      <CssBaseline />
      <AppBar
        position="fixed"
        sx={{
          width: { sm: `calc(100% - ${drawerWidth}px)` },
          ml: { sm: `${drawerWidth}px` },
        }}
      >
        <Toolbar>
          <IconButton
            color="inherit"
            aria-label="open drawer"
            edge="start"
            onClick={handleDrawerToggle}
            sx={{ mr: 2, display: { sm: "none" } }}
          >
            <MenuIcon />
          </IconButton>
        </Toolbar>
      </AppBar>
      <Box
        component="nav"
        sx={{ width: { sm: drawerWidth }, flexShrink: { sm: 0 } }}
        aria-label="mailbox folders"
      >
        <Drawer
          variant="temporary"
          open={mobileOpen}
          onTransitionEnd={handleDrawerTransitionEnd}
          onClose={handleDrawerClose}
          ModalProps={{
            keepMounted: true, // Better open performance on mobile.
          }}
          sx={{
            display: { xs: "block", sm: "none" },
            "& .MuiDrawer-paper": {
              boxSizing: "border-box",
              width: drawerWidth,
            },
          }}
        >
          <img src={jazzcashLogo} alt="Jazzcash Logo" />
          {drawer}
        </Drawer>
        <Drawer
          variant="permanent"
          sx={{
            display: { xs: "none", sm: "block" },
            border: "2px solid black",
            "& .MuiDrawer-paper": {
              boxSizing: "border-box",
              backgroundColor: "rgb(54,55,64)",
              width: drawerWidth,
            },
          }}
          open
        >
          {drawer}
        </Drawer>
      </Box>
    </Box>
  );
}
export default Admin;

useAuth.js

import { useContext } from "react";
import AuthContext from "../context/AuthProvider";

const useAuth = () => {
    return useContext(AuthContext);
}

export default useAuth;

AuthProvider.js

import { createContext, useState } from "react";

const AuthContext = createContext({});

export const AuthProvider = ({ children }) => {
    const [auth, setAuth] = useState({});

    return (
        <AuthContext.Provider value={{ auth, setAuth }}>
            {children}
        </AuthContext.Provider>
    )
}

export default AuthContext;

已尝试的解决方案

  • 排查过React Router v6嵌套路由渲染问题的相关方案
  • 将侧边栏的NavLink替换为Link,问题仍未解决

内容的提问来源于stack exchange,提问作者Sajeel Zafar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 03:54:55