React私有路由刷新跳转登录页,加载逻辑失效问题求助
问题
在React应用中使用Redux + RTK Query实现私有路由时,刷新私有页面会直接跳转到登录页,无法进入isLoading分支显示加载状态。虽然刷新后Redux Store的用户信息最终会更新,但导航跳转已经提前触发。
相关代码
RequireAuth组件代码
import { ReactNode } from "react"; import { useAppSelector } from "../../redux/hooks"; import { Navigate, useLocation } from "react-router-dom"; const RequireAuth = ({ children }: { children: ReactNode }) => { const location = useLocation(); const { user, isLoading } = useAppSelector((state) => state?.auth); if (isLoading) { return <p>Loading.............</p>; } if (!user?.email && !isLoading) { return <Navigate to="/login" state={{ from: location }}></Navigate>; } return children; }; export default RequireAuth;
Auth Slice初始状态与代码
import { createSlice } from "@reduxjs/toolkit"; const initialState = { user: { email: "", accountStatus: "", role: "", id: "", }, isLoading: false, }; const authSlice = createSlice({ name: "auth", initialState, reducers: { userLoggedIn: (state, action) => { const { accessToken, ...userInfo } = action.payload; state.user = userInfo; }, userLoggedOut: (state) => { state.user = { email: "", accountStatus: "", role: "", id: "", }; }, toggleLoading: (state) => { state.isLoading = !state.isLoading; }, }, }); export const { userLoggedIn, userLoggedOut, toggleLoading } = authSlice.actions; export default authSlice.reducer;
RTK Query persistLogin端点代码
const authApi = api.injectEndpoints({ endpoints: (builder) => ({ persistLogin: builder.query({ query: (payload) => ({ url: "/auth/persist-login", method: "GET", body: payload, }), async onQueryStarted(_data, { dispatch, queryFulfilled }) { try { dispatch(toggleLoading()); const result = await queryFulfilled; dispatch(userLoggedIn(result.data.data)); dispatch(toggleLoading()); } catch (error) { // nothing to do here } }, }), }), });
注:在App.tsx中调用
usePersistLoginQuery钩子,用于页面刷新时持久化用户信息。
修复方案
1. 修正初始加载状态的默认值
页面刷新后Redux Store重置为初始状态,此时user.email为空,且初始isLoading为false,导致RequireAuth直接触发跳转。将初始isLoading设为true,确保身份验证请求完成前先显示加载状态:
// authSlice.js const initialState = { user: { email: "", accountStatus: "", role: "", id: "", }, isLoading: true, // 改为true };
2. 改用RTK Query内置的加载状态(更可靠)
手动维护toggleLoading容易出现时机偏差,直接使用RTK Query钩子返回的isLoading状态,能精准对应请求的生命周期:
- 修改
RequireAuth组件:
import { ReactNode } from "react"; import { useAppSelector } from "../../redux/hooks"; import { Navigate, useLocation } from "react-router-dom"; import { usePersistLoginQuery } from "../../redux/services/authApi"; const RequireAuth = ({ children }: { children: ReactNode }) => { const location = useLocation(); const { user } = useAppSelector((state) => state?.auth); // 直接获取RTK Query的请求加载状态 const { isLoading } = usePersistLoginQuery(/* 传入persistLogin所需的payload,如localStorage中的token */); if (isLoading) { return <p>Loading.............</p>; } if (!user?.email) { return <Navigate to="/login" state={{ from: location }}></Navigate>; } return children; }; export default RequireAuth;
- 移除手动加载状态相关代码:
- 删除authSlice中的
toggleLoadingreducer及导出 - 删除
persistLogin端点中的dispatch(toggleLoading())调用
- 删除authSlice中的
3. 确保persistLogin请求的执行时机
在App.tsx中调用usePersistLoginQuery时,不要设置skip参数,确保应用初始化时立即触发身份验证请求:
// App.tsx import { usePersistLoginQuery } from "./redux/services/authApi"; function App() { // 直接调用钩子,页面加载时自动触发请求 usePersistLoginQuery(/* 传入必要的验证参数 */); return ( <Router> {/* 路由配置 */} </Router> ); }
核心原因
页面刷新后Redux Store重置,初始状态下user.email为空且isLoading为false,RequireAuth会立即执行跳转逻辑;而persistLogin是异步请求,完成后更新用户信息时,跳转已经完成。通过调整初始加载状态或依赖RTK Query的内置状态,可确保身份验证过程中先显示加载,再判断是否跳转。
内容的提问来源于stack exchange,提问作者Shakil Ahmed
相关产品推荐
相关产品推荐

