React受保护路由问题:登录后无法跳转至Dashboard
问题分析与解决方案
问题根源
核心问题在于:App组件初始化时一次性读取用户状态(getUser()),但登录设置Cookie后,App组件并未触发重新渲染,导致路由守卫使用的还是初始的未登录状态。因此首次登录跳转时会被拦截回登录页;而手动输入URL时,页面重新加载,App组件重新初始化,此时Cookie已存在,getUser()能正确读取角色信息,路由校验通过。
解决方案
需要让路由守卫的用户状态动态响应Cookie变化,而非仅在组件初始化时读取一次,以下是两种可行方案:
方案1:封装动态路由守卫组件
创建ProtectedSuperRoute组件,在组件内部实时检查用户状态,替代静态判断:
import React from "react"; import { Navigate, Outlet } from "react-router-dom"; import { getUser } from "./lib/jwtdecode"; function ProtectedSuperRoute() { const user = getUser(); const is_super = user?.super === true; // 实时判断用户权限 return is_super ? <Outlet /> : <Navigate to="/login" replace />; } export default ProtectedSuperRoute;
修改App组件的路由配置,使用该守卫组件:
import React from "react"; import { BrowserRouter, Navigate, Route, Routes } from "react-router-dom"; import DashboardLayout from "./components/layout/dashlayout"; import AdminDashboard from "./pages/admin/dashboard"; import PageNotFoundError from "./pages/404error"; import LoginPage from "./pages/auth/login"; import ListCompaniesPage from "./pages/admin/listcompanies"; import ListUsersPage from "./pages/admin/listusers"; import ProtectedSuperRoute from "./components/ProtectedSuperRoute"; function App() { return ( <BrowserRouter> <Routes> <Route path="*" element={<PageNotFoundError />} /> <Route path="/" element={<Navigate to="/login" replace />} /> <Route path="/login" element={<LoginPage />} /> {/* 使用动态路由守卫 */} <Route element={<ProtectedSuperRoute />}> <Route element={<DashboardLayout />}> <Route path="/dashboard" element={<AdminDashboard />} /> <Route path="/list-companies" element={<ListCompaniesPage />} /> <Route path="/list-users" element={<ListUsersPage />} /> {/* 其他路由 */} </Route> </Route> </Routes> </BrowserRouter> ); } export default App;
方案2:在App组件中监听Cookie变化,更新用户状态
若不想新增组件,可在App中用useState和useEffect监听Cookie变化,实时更新用户状态:
import React, { useState, useEffect } from "react"; import { BrowserRouter, Navigate, Route, Routes } from "react-router-dom"; import DashboardLayout from "./components/layout/dashlayout"; import AdminDashboard from "./pages/admin/dashboard"; import PageNotFoundError from "./pages/404error"; import LoginPage from "./pages/auth/login"; import ListCompaniesPage from "./pages/admin/listcompanies"; import ListUsersPage from "./pages/admin/listusers"; import { getUser } from "./lib/jwtdecode"; import Cookies from "js-cookie"; function App() { const [is_super, setIsSuper] = useState(false); // 监听Cookie变化,实时更新用户状态 useEffect(() => { const updateUserStatus = () => { const user = getUser(); setIsSuper(user?.super === true); }; // 初始化执行一次 updateUserStatus(); // 定时检查Cookie变化 const interval = setInterval(updateUserStatus, 500); return () => clearInterval(interval); }, []); return ( <BrowserRouter> <Routes> <Route path="*" element={<PageNotFoundError />} /> <Route path="/" element={<Navigate to="/login" replace />} /> <Route path="/login" element={<LoginPage />} /> <Route element={is_super ? <DashboardLayout /> : <Navigate to="/login" replace />}> <Route path="/dashboard" element={<AdminDashboard />} /> <Route path="/list-companies" element={<ListCompaniesPage />} /> <Route path="/list-users" element={<ListUsersPage />} /> {/* 其他路由 */} </Route> </Routes> </BrowserRouter> ); } export default App;
为什么之前的延迟跳转无效?
你尝试的loginSuccessful状态更新仅触发LoginPage组件重新渲染,但App组件的用户状态并未更新,路由守卫依然使用初始的is_super=false判断,因此跳转仍会被拦截。只有让App组件或路由守卫组件实时读取最新的Cookie状态,才能解决问题。
内容的提问来源于stack exchange,提问作者Sixcheviexx
相关产品推荐
相关产品推荐

