页面刷新(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
相关产品推荐
相关产品推荐

