如何将登录用户存入Redux状态?解决TOKEN初始化加载异常
问题解决:MERN+Redux Toolkit持久化后启动API调用提示用户不存在
问题背景
在MERN项目中使用Redux Toolkit存储当前用户信息,通过redux-persist将TOKEN保存在sessionStorage中,但每次启动应用调用需要TOKEN的API时,都会提示“error user is not existed”,核心原因是应用启动时redux-persist尚未完成持久化状态恢复,导致user对象未初始化、TOKEN无法正确获取。
代码问题分析
当前useFetch.js中存在两个关键问题:
- 静态TOKEN初始化时机错误:模块加载阶段直接读取sessionStorage,此时redux-persist还未完成状态恢复,
sessionStorage.getItem("persist:root")可能返回null,或解析后无currentUser字段,导致TOKEN为undefined。 - axios实例请求头固定:
userMethod初始化时就固定了请求头,后续Redux状态更新token后,实例不会自动同步最新值。
// 原useFetch.js的问题代码 const TOKEN = (JSON.parse(JSON.parse(sessionStorage.getItem("persist:root")).user).currentUser?.accessToken); export const userMethod = axios.create({ baseURL: BASE_URL, headers: {token: `Bearer ${TOKEN}`} })
解决方案
方案1:用axios请求拦截器动态获取token
修改useFetch.js,通过拦截器在每次请求时从Redux状态动态获取最新token,避免静态初始化的时机问题:
import axios from 'axios'; import store from './store'; // 导入你的Redux store实例 const BASE_URL = "http://localhost:5000"; export const publicRequest = axios.create({ baseURL: BASE_URL }) export const userMethod = axios.create({ baseURL: BASE_URL }) // 添加请求拦截器,动态注入token userMethod.interceptors.request.use( (config) => { const currentUser = store.getState().user.currentUser; if (currentUser) { config.headers.token = `Bearer ${currentUser.accessToken}`; } return config; }, (error) => Promise.reject(error) )
方案2:等待redux-persist完成状态恢复后渲染应用
在入口文件(如index.js)中使用PersistGate,确保Redux状态完全恢复后再渲染组件、发起API请求:
import React from 'react'; import ReactDOM from 'react-dom/client'; import { Provider } from 'react-redux'; import { PersistGate } from 'redux-persist/integration/react'; import { store, persistor } from './store'; // 你的store和persistor实例 import App from './App'; const root = ReactDOM.createRoot(document.getElementById('root')); root.render( <Provider store={store}> <PersistGate loading={null} persistor={persistor}> <App /> </PersistGate> </Provider> );
方案3:登录/登出时手动更新axios实例请求头
在Redux的user切片中,登录成功后更新userMethod的默认请求头,登出时清除,确保token实时同步:
// userRedux.js import { createSlice } from '@reduxjs/toolkit' import { userMethod } from '../useFetch'; const userSlice = createSlice({ name: "user", initialState: { currentUser: null, isFetching: false, error: false }, reducers: { loginStart: (state) => { state.isFetching = true; }, loginSuccess: (state, action) => { state.isFetching = false; state.currentUser = action.payload; // 更新axios实例的默认token userMethod.defaults.headers.token = `Bearer ${action.payload.accessToken}`; }, loginFailure: (state) => { state.isFetching = false; state.error = true; }, logout: (state) => { state.currentUser = null; // 清除请求头中的token delete userMethod.defaults.headers.token; } } }) export const { loginStart, loginSuccess, loginFailure, logout } = userSlice.actions export default userSlice.reducer;
内容的提问来源于stack exchange,提问作者RAHMAN DHIKA
相关产品推荐
相关产品推荐

