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

页面刷新(F5)后Redux-Toolkit无法获取token的问题求助

解决刷新页面后Redux中Token丢失导致的TypeError问题

问题原因

刷新页面时,Redux的内存状态会被清空,回到initialState中user: null的初始值。此时组件渲染时直接访问user.token,就会触发Cannot read properties of null (reading 'token')错误。

解决方案

1. 组件内添加防御性检查(即时修复)

在访问user.token前先判断user是否存在,避免直接读取null的属性:

const [users, setUsers] = useState([]);
const { user } = useSelector((state) => state.auth);

const getUsers = async () => {
  // 先校验token是否存在
  if (!user?.token) return;
  
  const response = await axios.get("http://localhost:5000/user",{
    headers: {
      Authorization: `Bearer ${user.token}`
    }
  });
  setUsers(response.data);
}

// 在useEffect中仅当user存在时调用接口
useEffect(() => {
  if (user?.token) {
    getUsers();
  }
}, [user]);

2. 持久化Redux状态(彻底解决刷新丢失)

将token存储到localStorage,初始化Redux状态时从本地读取,确保刷新后状态不会丢失:
修改你的authSlice代码:

// 初始化时从localStorage读取保存的用户信息
const initialState = {
    user: JSON.parse(localStorage.getItem('authUser')) || null,
    isError: false,
    isSuccess: false,
    isLoading: false,
    message: ""
}

export const authSlice = createSlice({
    name: "auth",
    initialState,
    reducers:{
        reset: (state) => {
            // 重置状态同时清空localStorage
            Object.assign(state, initialState);
            localStorage.removeItem('authUser');
        }
    },
    extraReducers:(builder) => {
        builder.addCase(getToken.pending, (state) => {
            state.isLoading = true; // 修正:pending状态应设为true
        })
        builder.addCase(getToken.fulfilled, (state, action) => {
            state.isLoading = false;
            state.isSuccess = true;
            state.user = action.payload;
            // 将用户信息存入localStorage
            localStorage.setItem('authUser', JSON.stringify(action.payload));
        });
        builder.addCase(getToken.rejected, (state, action) => {
            state.isLoading = false;
            state.isError = true;
            state.message = action.payload;
        });
    }
});

注意:你之前的getToken.pending里把isLoading设为false是错误的,应该改为true才符合加载状态的逻辑。

3. Axios拦截器最佳实践

统一处理请求头自动添加token、响应错误(如token过期),避免在每个接口中重复写header:
创建一个axios实例并配置拦截器:

// utils/axiosInstance.js
import axios from 'axios';

const axiosInstance = axios.create({
  baseURL: 'http://localhost:5000'
});

// 请求拦截器:自动给所有请求添加Authorization头
axiosInstance.interceptors.request.use(
  (config) => {
    const authUser = JSON.parse(localStorage.getItem('authUser'));
    if (authUser?.token) {
      config.headers.Authorization = `Bearer ${authUser.token}`;
    }
    return config;
  },
  (error) => Promise.reject(error)
);

// 响应拦截器:统一处理401(token过期/未授权)错误
axiosInstance.interceptors.response.use(
  (response) => response,
  (error) => {
    if (error.response?.status === 401) {
      // 清空本地存储和Redux状态,跳转到登录页
      localStorage.removeItem('authUser');
      // 这里可以调用Redux的reset action,或者直接跳转
      window.location.href = '/login';
    }
    return Promise.reject(error);
  }
);

export default axiosInstance;

之后在组件中使用这个实例,无需手动添加header:

import axiosInstance from './utils/axiosInstance';

const getUsers = async () => {
  // 不用手动设置Authorization头,拦截器会自动处理
  const response = await axiosInstance.get("/user");
  setUsers(response.data);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 18:46:18