如何避免Redux接收旧请求数据?React项目问题排查与修复
React+Redux Toolkit登录后立即退出问题排查与修复
问题描述
登录后进入Dashboard2组件会立即触发退出逻辑,核心原因是组件初始化时useSelector先获取到Redux中的旧状态(或初始状态),导致未授权判断被错误触发。
核心问题分析
- 初始状态不严谨:
authSlice的初始状态中user.data设为空字符串,组件初始化时user.data.success为undefined,!user.data.success会被判定为true,直接触发退出。 - 状态判断逻辑混乱:组件同时依赖
localStorage的token和Redux的user状态,两者未同步,登录后Redux状态未更新完成时,旧状态会触发错误判断。 - 退出处理不符合React规则:组件中
return window.localStorage.removeItem("token")会返回undefined,违反React组件必须返回JSX或null的要求。 - logout动作冗余:
logout中修改了未在初始状态定义的state.data字段,属于无效操作。
修复方案
1. 修正Redux Auth切片状态与动作
// slices/auth.js import {createSlice, createAsyncThunk} from "@reduxjs/toolkit"; import axios from "../../axios"; // ... 保留原有createAsyncThunk定义不变 const initialState = { user: { data: null, // 改为null,避免初始时success判断异常 status: 'loading', }, transactions: { data: null, status: 'loading', } }; const authSlice = createSlice({ name: 'auth', initialState, reducers: { logout: (state) => { // 只清理已定义的状态字段 state.user.data = null; state.user.status = 'loading'; state.transactions.data = null; state.transactions.status = 'loading'; // 统一在action中移除token,避免分散处理 window.localStorage.removeItem('token'); } }, // ... 保留原有extraReducers定义不变 }); export const authReducer = authSlice.reducer; export const {logout} = authSlice.actions
2. 重构Dashboard2组件逻辑
export const Dashboard2 = () => { const dispatch = useDispatch(); const {user, transactions} = useSelector((state) => state.auth); React.useEffect(() => { dispatch(fetchAuthMe()); dispatch(fetchAuthGetTransactions()); }, [dispatch]); // 添加dispatch依赖消除lint警告 // 优先处理加载状态,避免旧状态干扰判断 if (user.status === 'loading' || transactions.status === 'loading') { return <div>加载中...</div>; // 可替换为项目统一的加载组件 } // 结合localStorage和Redux状态判断授权有效性 const hasToken = Boolean(window.localStorage.getItem('token')); const isAuthSuccess = user.data?.success === true; const isAuthenticated = hasToken && isAuthSuccess; // 未授权时触发logout并重定向 if (!isAuthenticated) { dispatch(logout()); return <Navigate to="/auth"/>; } // 已授权且加载完成,渲染页面 return ( <div className=""> <div className="flex h-screen antialiased text-gray-900 bg-gray-100 dark:bg-dark dark:text-light"> <Aside/> <TopBar user={user.data} transactions={transactions.data}/> </div> </div> ); };
额外注意事项
- 确保Axios请求拦截器中正确携带token,避免
fetchAuthMe请求因无token返回未授权:// axios.js示例配置 axios.interceptors.request.use((config) => { const token = window.localStorage.getItem('token'); if (token) { config.headers.Authorization = `Bearer ${token}`; } return config; }); - 登录成功后,需同时将token存入
localStorage并更新Redux状态,确保两者同步。
内容的提问来源于stack exchange,提问作者Asas Vrunk
相关产品推荐
相关产品推荐

