React Router V6中使用Outlet实现私有路由的触发问题
问题分析与解决方案
核心原因
React Router 6中,作为布局路由的PrivateRoutes组件,在子路由(如/dashboard和/reports)之间导航时,并不会被卸载或重新挂载。React组件只有在自身的props、state或依赖的上下文发生变化时才会重新渲染,而子路由切换并不会触发父布局路由组件的这些变化,因此你的checkToken()只会在首次进入私有路由时执行一次。
解决方案:监听路由变化触发重新检查
通过react-router-dom提供的useLocation钩子监听路由地址变化,让PrivateRoutes在每次导航时重新执行鉴权逻辑:
修改PrivateRoutes组件:
import { Outlet, Navigate, useLocation } from 'react-router-dom'; const PrivateRoutes = () => { const location = useLocation(); // 捕获当前路由位置,每次导航都会生成新的location对象 console.log("Private Routes was run"); // 每次路由变化时重新校验token const isTokenValid = checkToken(); // 跳转时记录来源地址,方便登录后跳转回原页面 return isTokenValid ? ( <Outlet /> ) : ( <Navigate to="/" replace state={{ from: location }} /> ); };
原理说明
useLocation返回的location对象在每次路由导航时都会是一个全新的引用,React会检测到这个依赖变化,从而重新渲染PrivateRoutes组件,进而重新执行checkToken()逻辑。
额外优化点
如果你的checkToken是异步操作(比如从接口验证),可以结合useState和useEffect处理加载状态:
import { Outlet, Navigate, useLocation } from 'react-router-dom'; import { useState, useEffect } from 'react'; const PrivateRoutes = () => { const location = useLocation(); const [isTokenValid, setIsTokenValid] = useState(null); useEffect(() => { // 异步校验token const validateToken = async () => { const valid = await checkToken(); setIsTokenValid(valid); }; validateToken(); }, [location]); // 路由变化时重新执行 if (isTokenValid === null) { return <div>加载中...</div>; // 处理加载状态 } return isTokenValid ? ( <Outlet /> ) : ( <Navigate to="/" replace state={{ from: location }} /> ); };
内容的提问来源于stack exchange,提问作者Parker
相关产品推荐
相关产品推荐

