You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React手动输入URL时Redux Toolkit状态丢失及路由保护优化问题

解决方案

1. 解决Redux状态刷新丢失问题

Redux状态默认存储在内存中,页面刷新或手动输入URL会清空状态,因此需要将核心认证信息持久化到localStorage,并在应用启动时自动恢复状态。

修改authSlice.js

import { createSlice, current } from '@reduxjs/toolkit';

// 从localStorage读取初始认证状态
const loadAuthState = () => {
  try {
    const serializedState = localStorage.getItem('authState');
    if (!serializedState) {
      return {
        token: null,
        signupError: "",
        loginError: "",
        loading: false,
        loginLoading: false,
        userId: undefined
      };
    }
    return JSON.parse(serializedState);
  } catch (err) {
    console.error('加载认证状态失败:', err);
    return {
      token: null,
      signupError: "",
      loginError: "",
      loading: false,
      loginLoading: false,
      userId: undefined
    };
  }
};

// 将核心认证状态保存到localStorage
const saveAuthState = (state) => {
  try {
    const serializedState = JSON.stringify({
      token: state.token,
      userId: state.userId
    });
    localStorage.setItem('authState', serializedState);
  } catch (err) {
    console.error('保存认证状态失败:', err);
  }
};

const authSlice = createSlice({
  name: "auth",
  initialState: loadAuthState(),
  reducers: {
    registerToken: (state, { payload }) => {
      state.token = payload.accessToken;
      state.userId = payload.id;
      saveAuthState(state);
    },
    loginToken: (state, { payload }) => {
      state.token = payload.accessToken;
      state.userId = payload.id;
      saveAuthState(state);
      console.log(current(state));
    },
    setLoading: (state, { payload }) => { state.loading = payload; },
    setRegisterError: (state, { payload }) => { state.signupError = payload; },
    setLoginError: (state, { payload }) => { state.loginError = payload; },
    setLoginLoading: (state, { payload }) => { state.loginLoading = payload; },
    setToken: (state, { payload }) => {
      state.token = payload;
      saveAuthState(state);
      console.log(current(state));
    },
    logoutToken: (state) => {
      state.token = null;
      state.userId = null;
      localStorage.removeItem('authState');
    }
  }
});

export const { registerToken, loginToken, setLoading, setRegisterError, setLoginError, setLoginLoading, setToken, logoutToken } = authSlice.actions;
export default authSlice.reducer;

2. 优化AuthGuard避免错误重定向

应用初始化时状态从localStorage读取存在极短延迟,添加加载状态避免用户被错误跳转:

修改authGuard.js

import { useSelector } from 'react-redux';
import { Navigate, useLocation } from 'react-router-dom';

function AuthGuard({ children }) {
  const { userId, loading } = useSelector(state => state.authReducer);
  const location = useLocation();

  // 加载中显示占位组件,替换为你的自定义加载UI
  if (loading) {
    return <div>加载中...</div>;
  }

  if (!userId) {
    // 保存当前访问路径,登录后跳转回来
    return <Navigate to="/signin" state={{ from: location.pathname }} />;
  }
  return <> {children} </>;
}

export default AuthGuard;

3. 处理已登录用户访问登录页的跳转逻辑

修改Login组件,检测到用户已登录时自动跳转到上次访问页面或默认仪表盘:

改造Login组件核心逻辑

import { useSelector } from 'react-redux';
import { Navigate, useLocation } from 'react-router-dom';

function Login() {
  const { userId } = useSelector(state => state.authReducer);
  const location = useLocation();
  
  // 优先使用之前保存的跳转路径,默认跳转到仪表盘
  const targetPath = location.state?.from || '/dashboard';

  // 已登录状态直接跳转
  if (userId) {
    return <Navigate to={targetPath} replace />;
  }

  // 原有登录表单代码
  return (
    // 你的登录表单UI及逻辑
  );
}

export default Login;

4. 路由配置说明

当前路由配置无需修改:登录/注册页面不受AuthGuard保护,仪表盘下所有子路由均通过AuthGuard的MainLayout统一控制权限,符合需求。


内容的提问来源于stack exchange,提问作者jsBug

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 00:02:39