解决Cannot read properties of null (reading 'user')报错 实现先登录再读localStorage token
问题根源
你代码中的TOKEN变量在requestMethod.js模块被引入时就会立即执行localStorage读取逻辑,此时用户尚未完成登录,localStorage.getItem('persist:root')返回值为null,后续读取null.user就会触发Cannot read properties of null (reading 'user')报错。
修复步骤
1. 重构requestMethod.js,使用请求拦截器动态获取Token
不要在axios实例初始化时就把Token写死在header中,改为每次发起鉴权请求前动态读取Token,同时增加判空逻辑避免未登录时的解析报错:
import axios from 'axios' const BASE_URL = 'http://localhost:5000/api' // 公共请求实例,无需携带Token,用于登录等公开接口 export const publicRequest = axios.create({ baseURL: BASE_URL, }) // 鉴权请求实例,通过拦截器动态注入Token export const userRequest = axios.create({ baseURL: BASE_URL, }) // 新增请求拦截器 userRequest.interceptors.request.use( (config) => { const persistRoot = localStorage.getItem('persist:root') // 仅当本地存在持久化存储时才尝试解析Token if (persistRoot) { try { const userStore = JSON.parse(JSON.parse(persistRoot).user) const accessToken = userStore?.currentUser?.accessToken if (accessToken) { config.headers.token = `Bearer ${accessToken}` } } catch (err) { // 解析失败不阻断请求,后续接口返回401时可全局处理跳登录 console.error('Token解析异常', err) } } return config }, (error) => Promise.reject(error) )
2. 修复Login.jsx的跳转逻辑
当前login方法是异步执行的,调用后立刻跳转页面会导致Redux还未完成数据持久化到localStorage,后续页面的鉴权请求无法拿到最新Token,需要等待登录逻辑执行完成后再跳转:
const handleClick = async (e) =>{ e.preventDefault() // 等待登录请求、Redux存储完成后再跳转 await login(dispatch,{username,password}) history.push('/home') }
3. 简化apicalls.js的登录逻辑
redux-persist会自动将loginSuccess传入的用户数据持久化到localStorage,不需要手动读取Token,删除冗余代码即可:
import { loginFailure, loginStart, loginSuccess } from './userRedux' import { publicRequest } from '../../requestMethod' export const login = async (dispatch, user) => { dispatch(loginStart()) try { const res = await publicRequest.post('/auth/login', user) dispatch(loginSuccess(res.data)) return res.data } catch (error) { dispatch(loginFailure()) return Promise.reject(error) } }
补充优化点
- 可以给axios新增全局响应拦截器,当接口返回401无权限状态码时,自动清空本地存储并跳转到登录页
- 路由层面增加守卫逻辑,未登录状态下仅允许访问登录页,避免用户手动输入内部路由地址直接访问
内容的提问来源于stack exchange,提问作者s_sldiblood
相关产品推荐
相关产品推荐

