React Router Dom中useEffect执行前触发路由重定向问题
问题根源
- React 执行顺序固定:组件首次挂载渲染完成后,才会执行
useEffect内的副作用逻辑,当前写法等接口发起请求时,首次渲染已经走完。 - 仅用
boolean类型的token状态无法覆盖三种场景:鉴权校验中、校验通过、校验不通过。初始值设为false会直接命中未登录重定向逻辑,哪怕后续接口返回有效鉴权结果,已经触发的跳转也不会自动回退。 - 附带小问题:Express 端用
res.send(true)返回的是text/plain格式响应,前端调用res.json()解析时可能抛出格式错误,建议返回标准JSON格式。
修复实现
后端接口调整
app.post('/refresh_token_from_db', async (req: Request, res: Response) => { // 改用json方法返回标准JSON格式,匹配前端解析逻辑 res.json(true) })
路由守卫组件调整
核心是新增加载状态,拦截首次渲染时的跳转逻辑,等鉴权结果返回后再做路由判断:
import { Navigate, Outlet } from 'react-router-dom' import { useState, useEffect } from 'react'; function ProtectedRoutes() { const [token, setToken] = useState<boolean>(false); // 初始设为加载中状态,避免首次渲染直接触发跳转 const [isAuthChecking, setIsAuthChecking] = useState<boolean>(true); useEffect(() => { const checkTokenValid = async () => { try { const res = await fetch('/refresh_token_from_db', { method: 'POST', mode: 'same-origin', redirect: 'follow', credentials: 'same-origin', headers: { 'content-type': 'application/json', 'Accept': 'application/json' }, }); const authResult = await res.json(); setToken(authResult); } catch (err) { console.error('鉴权请求异常:', err); setToken(false); } finally { // 请求完成(无论成功失败)结束加载状态 setIsAuthChecking(false); } } checkTokenValid(); }, []); // 鉴权未完成时,展示加载占位,不执行路由判断 if (isAuthChecking) { return <div>权限校验中...</div> } // 鉴权完成后再根据结果选择渲染受保护路由或跳转登录 return token ? <Outlet /> : <Navigate to="/login" replace />; } export default ProtectedRoutes
关键逻辑说明
- 拆分
isAuthChecking状态专门标记鉴权请求进度,首次渲染时不会命中跳转逻辑 - 接口请求过程中展示轻量加载提示,避免页面空白
finally块统一处理加载状态收尾,不管请求成功、失败都不会卡在加载页- 给
Navigate组件加上replace属性,替换当前路由栈记录,避免用户点击浏览器返回键时陷入鉴权判断的死循环
内容的提问来源于stack exchange,提问作者Owen Delisle
相关产品推荐
相关产品推荐

