如何使用react-router-dom在每次路由重定向时调用指定函数
最符合开发规范的方案是把Cookie校验逻辑收敛到路由拦截层统一处理,完全不需要在每个路由对应的业务组件里重复写调用代码,这种实现也符合单一职责原则,后续修改校验规则只需要改一处即可。根据你使用的react-router-dom版本选择对应写法即可,目前主流是v6版本。
v6版本实现(当前官方维护的主流版本)
有两种通用写法,根据业务场景选就行:
封装鉴权包装组件(适合仅部分路由需要Cookie校验的场景)
先写一个通用的路由校验组件,所有需要做Cookie检查的路由都用这个组件包裹,路由跳转进入对应页面前会先执行校验逻辑,校验通过才渲染业务内容,校验失败直接重定向到指定页面(比如登录页)。import { Navigate, useLocation, Outlet } from 'react-router-dom'; // 引入你自己封装的Cookie校验方法 import { checkCookieValid } from '@/utils/auth'; // 通用Cookie校验包装组件 function RequireCookieCheck() { const location = useLocation(); const cookieValid = checkCookieValid(); if (!cookieValid) { // 校验不通过重定向到登录页,同时记录当前访问路径,登录后可直接跳回 return <Navigate to="/login" state={{ from: location }} replace />; } // 嵌套的子路由会渲染在Outlet位置 return <Outlet />; }路由配置时直接套在需要校验的路由外层即可,后续新增需要校验的业务路由直接往里面加就行,不用重复写校验逻辑:
import { Routes, Route } from 'react-router-dom'; function AppRouter() { return ( <Routes> {/* 公共路由无需校验,直接放在外层,比如登录页 */} <Route path="/login" element={<Login />} /> {/* 需要Cookie校验的路由统一放在包装组件内部 */} <Route element={<RequireCookieCheck />}> <Route path="/" element={<Home />} /> <Route path="/dashboard" element={<Dashboard />} /> <Route path="/profile" element={<Profile />} /> {/* 其余业务路由都可以加在这里 */} </Route> </Routes> ); }全局路由守卫(适合所有路由跳转都要触发Cookie检查的场景)
如果不管访问什么页面,只要路由发生变化就要做Cookie校验,可以直接封装一个全局监听组件,放在路由容器的最顶层,每次路由路径变化就自动触发校验逻辑,不用逐个包裹路由。import { useEffect } from 'react'; import { useLocation, useNavigate } from 'react-router-dom'; import { checkCookieValid } from '@/utils/auth'; function GlobalRouterGuard() { const location = useLocation(); const navigate = useNavigate(); useEffect(() => { const cookieValid = checkCookieValid(); // 配置不需要重定向的白名单路径,比如登录页 const pathWhiteList = ['/login']; if (!cookieValid && !pathWhiteList.includes(location.pathname)) { navigate('/login', { replace: true }); } // 其他全局路由逻辑比如页面埋点、重置页面标题也可以写在这里 }, [location.pathname, navigate]); return null; }使用时直接把这个守卫组件放在
BrowserRouter/HashRouter内部的最顶层即可:import { BrowserRouter, Routes, Route } from 'react-router-dom'; function App() { return ( <BrowserRouter> {/* 全局守卫要放在Routes外层,确保所有路由跳转都能被监听到 */} <GlobalRouterGuard /> <Routes> <Route path="/login" element={<Login />} /> <Route path="/" element={<Home />} /> {/* 其余路由配置 */} </Routes> </BrowserRouter> ); }
v5及更早版本实现
已经停止维护的v5版本可以直接在路由配置项里使用onEnter钩子,把Cookie校验逻辑传入即可,不过更建议升级到v6版本使用上述方案。
注意:Cookie校验、权限判断这类和具体业务逻辑无关的路由前置逻辑,不要散落在各个业务组件中,否则后续调整规则时需要修改大量文件,维护成本极高,统一收敛到路由拦截层是行业通用的最佳实践。
内容的提问来源于stack exchange,提问作者Dylan Yurjevich

