React路由访问限制实现:需先访指定路径且用Context管理状态
实现方案
核心思路是用Context管理访问状态,结合sessionStorage实现刷新持久化(你排除了localStorage,sessionStorage是前端轻量的替代方案,页面刷新后数据保留,关闭标签页才清除),再配合React Router的路由守卫控制路由访问权限。
1. 创建访问状态Context
定义Context存储已访问路由列表,同时实现状态的更新与持久化同步:
import { createContext, useContext, useState, useEffect, useMemo } from 'react'; const RouteAccessContext = createContext(); export function RouteAccessProvider({ children }) { // 从sessionStorage初始化状态,页面刷新时恢复数据 const [visitedRoutes, setVisitedRoutes] = useState(() => { const saved = sessionStorage.getItem('visitedRoutes'); return saved ? JSON.parse(saved) : []; }); // 状态变化时同步到sessionStorage useEffect(() => { sessionStorage.setItem('visitedRoutes', JSON.stringify(visitedRoutes)); }, [visitedRoutes]); // 标记路由为已访问 const markRouteAsVisited = (routePath) => { if (!visitedRoutes.includes(routePath)) { setVisitedRoutes(prev => [...prev, routePath]); } }; // 检查是否已访问指定路由 const hasVisitedRoute = (routePath) => { return visitedRoutes.includes(routePath); }; // 用useMemo优化,避免不必要的组件重渲染 const contextValue = useMemo(() => ({ visitedRoutes, markRouteAsVisited, hasVisitedRoute }), [visitedRoutes]); return ( <RouteAccessContext.Provider value={contextValue}> {children} </RouteAccessContext.Provider> ); } // 自定义钩子,简化组件调用 export function useRouteAccess() { return useContext(RouteAccessContext); }
2. 包裹应用根组件
将整个应用用RouteAccessProvider包裹,确保所有路由和组件能访问Context状态:
import { RouteAccessProvider } from './RouteAccessContext'; import { BrowserRouter } from 'react-router-dom'; function App() { return ( <BrowserRouter> <RouteAccessProvider> {/* 你的路由和业务组件 */} </RouteAccessProvider> </BrowserRouter> ); } export default App;
3. 实现路由守卫组件
创建ProtectedRoute组件,用于校验用户是否满足访问条件:
import { Navigate, Outlet } from 'react-router-dom'; import { useRouteAccess } from './RouteAccessContext'; // requiredRoute:必须访问过的前置路由;fallbackPath:权限不足时跳转的路径 export function ProtectedRoute({ requiredRoute, fallbackPath = '/' }) { const { hasVisitedRoute } = useRouteAccess(); const isAllowed = hasVisitedRoute(requiredRoute); return isAllowed ? <Outlet /> : <Navigate to={fallbackPath} replace />; }
4. 标记前置路由访问状态
在需要追踪访问状态的前置路由组件中,调用markRouteAsVisited更新状态:
import { useEffect } from 'react'; import { useRouteAccess } from './RouteAccessContext'; function PreRoute() { const { markRouteAsVisited } = useRouteAccess(); useEffect(() => { // 标记当前路由为已访问 markRouteAsVisited('/pre-route'); }, [markRouteAsVisited]); return <div>这是前置路由,访问后才能进入目标路由</div>; } export default PreRoute;
5. 配置路由规则
在路由配置中用ProtectedRoute包裹需要权限的路由:
import { Routes, Route } from 'react-router-dom'; import PreRoute from './PreRoute'; import TargetRoute from './TargetRoute'; import Home from './Home'; import { ProtectedRoute } from './ProtectedRoute'; function RoutesConfig() { return ( <Routes> <Route path="/" element={<Home />} /> <Route path="/pre-route" element={<PreRoute />} /> {/* 只有访问过/pre-route,才能进入/target-route */} <Route element={<ProtectedRoute requiredRoute="/pre-route" fallbackPath="/pre-route" />}> <Route path="/target-route" element={<TargetRoute />} /> </Route> </Routes> ); } export default RoutesConfig;
关键细节说明
- 若需要跨标签页共享访问状态,可将sessionStorage替换为cookie;若仅需单标签页内持久化,sessionStorage足够轻量。
- 确保标记的路由路径与路由配置中的路径完全一致(比如带斜杠、参数格式),避免匹配失败。
- 若应用规模较大,可结合
useCallback优化markRouteAsVisited方法,进一步减少重渲染。
内容的提问来源于stack exchange,提问作者Shamal Weerasooriya
相关产品推荐
相关产品推荐

