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
}
},
}),
}),
});
