React Router JWT认证登出重定向/login路由匹配错误求助
问题原因
当点击Logout组件执行navigate("/login")时,Auth Context中的token还未完成更新,此时Routes组件拿到的token仍是有效值,路由配置里只包含routesForPublic和routesForAuthenticatedOnly,而/login路由仅存在于routesForNotAuthenticatedOnly中,导致React Router找不到匹配的路由,抛出错误。
原代码采用静态拼接路由的方式,路由配置依赖初始的token值,登出时token更新后不会立即重新生成路由配置,进而引发导航时路由不存在的问题。
解决方案
方案1:将/login路由设为公共路由
把/login从routesForNotAuthenticatedOnly移到routesForPublic,确保无论用户是否认证,/login路由始终存在:
修改Routes.jsx中的routesForPublic:
const routesForPublic = [ { path: "/service", element: <div>Service Page</div>, }, { path: "/about-us", element: <div>About Us</div>, }, { path: "/login", element: <Login/>, }, ];
同时修改routesForNotAuthenticatedOnly,移除/login项:
const routesForNotAuthenticatedOnly = [ { path: "/", element: <div>Home Page</div>, }, ];
如果需要避免已登录用户访问登录页,可以在Login组件内添加判断:若存在token则重定向到首页。
方案2:确保token更新后再执行导航
修改Logout组件,等待token被清除后再触发导航:
假设Auth Provider的logout方法如下:
// authProvider.jsx示例 const logout = () => { localStorage.removeItem("token"); setToken(null); };
在Logout组件中通过useEffect监听token变化,完成清除后再导航:
// Logout.jsx import { useEffect } from "react"; import { useAuth } from "../provider/authProvider"; import { useNavigate } from "react-router-dom"; const Logout = () => { const { token, logout } = useAuth(); const navigate = useNavigate(); useEffect(() => { if (!token) { navigate("/login", { replace: true }); } }, [token, navigate]); const handleLogout = () => { logout(); }; return <button onClick={handleLogout}>Logout</button>; }; export default Logout;
方案3:改用动态路由保护逻辑(推荐)
放弃静态拼接路由的方式,统一定义所有路由,通过组件内的逻辑控制访问权限:
修改Routes.jsx:
import { RouterProvider, createBrowserRouter } from "react-router-dom"; import { ProtectedRoute } from "./ProtectedRoute"; import { PublicRoute } from "./PublicRoute"; import Login from "../pages/Login"; import Logout from "../pages/Logout"; const router = createBrowserRouter([ { path: "/service", element: <div>Service Page</div>, }, { path: "/about-us", element: <div>About Us</div>, }, { path: "/", element: ( <PublicRoute> <div>Home Page</div> </PublicRoute> ), }, { path: "/login", element: ( <PublicRoute> <Login /> </PublicRoute> ), }, { path: "/", element: <ProtectedRoute />, children: [ { path: "", element: <div>User Home Page</div> }, { path: "profile", element: <div>User Profile</div> }, { path: "logout", element: <Logout /> }, ], }, ]); const Routes = () => { return <RouterProvider router={router} />; }; export default Routes;
新增PublicRoute组件:
// PublicRoute.jsx import { Navigate, Outlet } from "react-router-dom"; import { useAuth } from "../provider/authProvider"; export const PublicRoute = ({ children }) => { const { token } = useAuth(); if (token) { return <Navigate to="/" replace />; } return children || <Outlet />; };
这种方式路由配置固定,通过组件逻辑控制访问权限,彻底避免动态拼接路由带来的导航错误。
总结
方案1是最直接的解决方式;若需要严格控制登录页的访问权限,方案3的写法更简洁且不易出错。
内容的提问来源于stack exchange,提问作者byles1506

