网站搜索

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