React+Redux+Axios页面刷新后跳转登录页问题排查
问题原因与解决方案
核心问题
- Redux状态属于内存存储,页面刷新后会被重置,
isLoggedIn会回到初始的false,此时App组件直接渲染登录路由,未先验证本地存储的token是否有效。 - 缺少页面初始化阶段的token校验与Redux状态同步逻辑,导致刷新后Redux状态与实际登录状态不一致。
解决方案
1. 添加初始化状态同步逻辑
在App组件中通过useEffect在页面加载时,检查本地存储的token并同步Redux登录状态:
// App.jsx 中新增 useEffect 逻辑 import axiosInstance from "./axios"; // 导入axios实例 function App() { const isLoggedIn = useSelector((state) => state.auth.isLoggedIn); const dispatch = useDispatch(); const navigate = useNavigate(); const [isLoading, setIsLoading] = useState(true); // 添加加载状态 useEffect(() => { const initAuth = async () => { const refreshToken = localStorage.getItem("refresh_token"); const accessToken = localStorage.getItem("access_token"); if (refreshToken || accessToken) { try { // 调用后端验证接口确认token有效性 await axiosInstance.get("/auth/validate"); dispatch(login()); // 同步Redux登录状态 } catch (err) { // 验证失败则清除token并登出 dispatch(logout()); localStorage.clear(); } } setIsLoading(false); }; initAuth(); }, [dispatch]); if (isLoading) { return <div>加载中...</div>; // 可替换为自定义加载组件 } // 原路由渲染代码不变 }
2. 优化路由渲染逻辑
通过加载状态避免刷新时短暂显示登录页,提升用户体验。
3. 修复Axios拦截器全局重试计数问题
全局retryCount会导致并发请求重试冲突,将计数存储在请求config中:
// axios.js 中修改响应拦截器 axiosInstance.interceptors.response.use( (response) => response, async (error) => { const originalRequest = error?.config; if (error.response.status === 401 && !originalRequest?._retry) { // 重试计数绑定到当前请求,避免全局冲突 originalRequest._retryCount = (originalRequest._retryCount || 0) + 1; if (originalRequest._retryCount < MAX_RETRY_COUNT) { originalRequest._retry = true; const newToken = await refreshAccessToken(); originalRequest.headers.Authorization = `Bearer ${newToken}`; return axiosInstance(originalRequest); } } // 重试失败后执行登出逻辑 if (error.response.status === 401) { store.dispatch(logout()); localStorage.clear(); window.location.href = "/"; } return Promise.reject(error); } );
4. 确认Redux Auth初始状态
检查Auth reducer的初始状态,确保isLoggedIn默认值为false,且login/logout动作能正确修改该状态:
// authReducer.js 示例 const initialState = { isLoggedIn: false, // 其他相关状态 }; export default function authReducer(state = initialState, action) { switch (action.type) { case "LOGIN": return { ...state, isLoggedIn: true }; case "LOGOUT": return { ...state, isLoggedIn: false }; default: return state; } }
内容的提问来源于stack exchange,提问作者raio
相关产品推荐
相关产品推荐

