reactjs - 在私有路由中重新加载会将用户带到登录页面
我正在尝试在 React 应用中实现一个私有路由。我正在使用 Redux 和 Redux-Toolkit (RTK) Query 来进行状态管理和数据获取。现在当我在私有页面刷新时,它会将我导航到登录页面,并且不会进入 if (isLoading) { return <p>Loading.............</p>; } 条件中。
当我重新加载页面时,用户信息在 redux 存储中已更新,但我也被导航到登录页面。我该如何解决这个问题?
这是 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;
这是初始状态:
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 端点:
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
isLoading 状态值最初为 false,因此应用程序以及您正在保护的路由,最初处于非加载状态。
从假定的加载状态开始。你可能也应该更明确地说明加载状态被设置为什么,而不仅仅是切换。
const initialState = {
user: {
email: "",
accountStatus: "",
role: "",
id: "",
},
isLoading: true, // <-- initially loading
};
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, action) => {
state.isLoading = action.payload;
},
},
});
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(true)); // <-- start loading
const result = await queryFulfilled;
dispatch(userLoggedIn(result.data.data));
} catch (error) {
// nothing to do here
} finally {
dispatch(toggleLoading(false)); // <-- clear loading
}
},
}),
}),
});
