React Router 5.2.0 页面刷新后如何保持停留在当前受保护路由
问题根源
你遇到的问题本质是鉴权状态初始化时机晚于首次路由渲染,导致首次渲染时误判为未登录触发重定向,等鉴权状态更新后当前路径已经被篡改,无法匹配原始访问路径。
你的checkIfAuthenticated是读取localStorage的同步操作,完全不需要放到useEffect里执行,挂载后才执行的逻辑导致首次渲染时isAuthenticated始终是初始的false,执行顺序如下:
- 页面刷新,访问
/staff?page=1,组件初始化,isAuthenticated = false - 首次渲染,走未登录分支,当前路径不匹配
/login,触发重定向到/login,路由地址被修改 - 之后
useEffect执行,调用checkIfAuthenticated发现有有效token,将isAuthenticated改为true - 组件重新渲染走已登录分支,此时路由地址已经是
/login,匹配不到受保护路由,触发默认重定向到/clients
解决方案
方案1:提前同步初始化鉴权状态(推荐)
直接在组件初始化阶段就执行鉴权逻辑,不要放到useEffect里,保证首次渲染时鉴权状态是正确的:
// 组件初始化时直接同步执行鉴权,不要放在useEffect中 checkIfAuthenticated(); const newHistory = useHistory() return <Router history={newHistory}> {isAuthenticated ? ( <Layout> <Switch> <Route exact path="/clients" component={Clients} /> <Route exact path="/staff" component={Staff} /> <Redirect to="/clients" /> </Switch> </Layout> ) : ( <> <Route path="/login" component={Login} /> <Redirect to="/login" /> </> )} </Router>
改完后首次渲染就能拿到正确的鉴权状态,刷新/staff?page=1时会直接匹配到对应路由,不会触发多余重定向。
方案2:增加加载态避免首次误判
如果后续你的鉴权逻辑可能改成异步(比如需要调用后端接口校验token有效性),可以加一个加载状态,鉴权完成前不渲染路由逻辑,避免误重定向:
const [authLoading, setAuthLoading] = useState(true); useEffect(() => { checkIfAuthenticated(); setAuthLoading(false); }, []); const newHistory = useHistory() // 鉴权完成前渲染加载占位,不触发路由逻辑 if (authLoading) return <div>加载中...</div> return <Router history={newHistory}> {/* 原有路由逻辑保持不变 */} </Router>
方案3:持久化原始访问路径(适合登录后回跳场景)
如果需要处理未登录用户访问受保护路径、登录后自动跳回原页面的需求,可以在重定向到登录页时把当前路径存到路由参数或者localStorage中:
// 未登录分支的Redirect改成携带原始访问路径参数 <Redirect to={`/login?from=${encodeURIComponent(window.location.pathname + window.location.search)}`} /> // 登录成功后读取参数跳转 const query = new URLSearchParams(useLocation().search); const from = decodeURIComponent(query.get('from') || '/clients'); history.push(from);
关于是否需要将路由存到localStorage
如果只是解决登录态有效时刷新停留在当前页的问题,完全不需要,用方案1就可以完美解决。只有需要处理未登录用户登录后回跳的场景,才需要持久化访问路径。
内容的提问来源于stack exchange,提问作者Sasha Zoria
相关产品推荐
相关产品推荐

