網站搜尋

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