React JS中token为空时调用navigate跳转/login报错如何解决
问题描述
在React JS项目中需要实现:当localStorage中存储的token为空时,自动跳转至/login登录页,实际运行时出现报错:
You should call navigate() in a React.useEffect(), not when your component is first rendered.
对应出问题的原始Main.js代码:
function Main() { const token = localStorage.getItem("token"); const navigate = useNavigate(); if (token == null) { navigate("/login"); } return ( <div> {token && <AdminHeader />} <Routes> <Route path="/" element={<HomePage />}></Route> <Route path="/login" element={<Login />}></Route> <Route path="/admin/" element={token && <AdminPage />}> <Route path="/admin/add-post" element={token && <AddPost />}></Route> <Route path="/admin/update-post" element={token && <UpdatePost />} ></Route> <Route path="/admin/add-country" element={token && <AddCountry />} ></Route> <Route path="/admin/post-list" element={token && <ListPost />} ></Route> </Route> </Routes> </div> ); } export default Main;
问题原因
- 核心错误是在组件渲染的同步执行阶段直接调用了
navigate()方法。React Router规定导航属于副作用操作,不能在组件首次渲染、函数组件同步执行的过程中触发,必须放到useEffect这类副作用钩子中执行,否则会打断React正常的渲染流程,触发上述报错。 - 原代码中
token && <AdminPage />这类写法存在逻辑漏洞:当token为空时,路由对应渲染的内容是null,页面会直接显示空白,不会按预期触发跳转。 - 嵌套路由重复写全量路径
/admin/xxx属于冗余写法,容易出现路径拼接错误。
修正方案
- 将token校验、跳转的逻辑全部移入
useEffect钩子中,将token和navigate设为依赖项,保证token状态变化时自动执行校验逻辑 - 跳转时增加
replace: true配置,替换当前路由栈记录,避免用户点击浏览器返回键时回到无权限的页面造成循环跳转 - 受保护路由使用
<Navigate>组件做兜底重定向,替代原有的token && 组件写法,避免出现空白页 - 嵌套路由使用相对路径写法,减少路径书写错误
修正后的完整代码:
import { useEffect } from 'react'; import { Routes, Route, useNavigate, Navigate } from 'react-router-dom'; // 其他业务组件导入省略 function Main() { const token = localStorage.getItem("token"); const navigate = useNavigate(); // 导航副作用放到useEffect中执行 useEffect(() => { if (!token) { navigate("/login", { replace: true }); } }, [token, navigate]); return ( <div> {token && <AdminHeader />} <Routes> <Route path="/" element={<HomePage />} /> <Route path="/login" element={<Login />} /> <Route path="/admin" element={token ? <AdminPage /> : <Navigate to="/login" replace />} > <Route path="add-post" element={<AddPost />} /> <Route path="update-post" element={<UpdatePost />} /> <Route path="add-country" element={<AddCountry />} /> <Route path="post-list" element={<ListPost />} /> </Route> </Routes> </div> ); } export default Main;
内容的提问来源于stack exchange,提问作者Demi God
相关产品推荐
相关产品推荐

