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

Redux Async Thunk登出pending、token报错、删除目标失效排查

问题现象
  • 执行账号登出操作时,登出流程始终卡在pending状态,其余业务流程表面无异常
  • 控制台持续抛出错误:Cannot read properties of null (reading 'token') Dashboard.jsx:20
  • 页面出现无限重渲染问题
  • 目标删除功能无法正常工作
  • 已知登出逻辑对应reducer代码:builder.addCase(logout.fulfilled, state => {state.user = null});
根因定位

共存在3处独立代码缺陷,共同触发上述所有异常:

  1. Dashboard组件useEffect逻辑缺陷触发死循环
    useEffect依赖项包含user、isError、message,但内部逻辑未对用户未登录场景做拦截:登出操作触发后user被置为null,组件依然会执行dispatch(getGoals())发起目标列表请求;请求失败后会更新isError、message状态,两个值变化又会触发useEffect重新执行,再次发起请求形成无限循环,直接导致页面无限重渲染、登出流程卡住。
  2. 所有目标相关异步thunk缺失空值校验
    createGoal、getGoals、deleteGoal三个异步thunk中,直接读取thunkAPI.getState().auth.user.token,登出后user为null,读取token属性直接触发空指针错误,和控制台报错信息完全匹配。
  3. 删除目标接口请求方法错误
    goalService.js中删除目标的逻辑错误使用axios.get发起请求,RESTful规范下删除资源需要使用axios.delete方法,GET请求无法触发后端删除逻辑,直接导致删除功能失效。
修复方案

按以下顺序修改对应文件即可解决全部问题:

  1. 修复Dashboard.jsx的useEffect逻辑
    增加未登录场景的拦截,用户不存在时直接跳转登录页、终止后续请求发起逻辑,修改后useEffect代码如下:
useEffect(() => {
    if (isError) console.log(message);
    if (!user) {
        navigate('/login');
        // 未登录状态不发起目标数据请求,终止执行
        return;
    }

    dispatch(getGoals());

    return () => {
        dispatch(reset());
    };
}, [user, isError, message, navigate, dispatch]);
  1. 给所有目标相关thunk增加空值保护
    修改goalSlice.js中三个异步thunk的token读取逻辑,先判断user是否存在,避免空指针,以getGoals为例:
export const getGoals = createAsyncThunk('goals/get', async (_, thunkAPI) => {
    try {
        const user = thunkAPI.getState().auth.user;
        if (!user) return thunkAPI.rejectWithValue('用户未登录');
        const token = user.token;
        return await goalService.getGoals(token);
    } catch (error) {
        const message =
            (error.response && error.response.data && error.response.data.message) ||
            error.message ||
            error.toString();
        return thunkAPI.rejectWithValue(message);
    }
});

createGoal、deleteGoal两个thunk做相同修改,先取user判空,再读取token发起请求。

  1. 修复删除目标的请求方法
    修改goalService.js中的删除逻辑,将GET请求替换为DELETE请求:
// Delete goal
const deleteGoal = async (goalId, token) => {
    const config = {
        headers: {
            'x-auth-token': `${token}`,
        },
    };
    // 原代码错误使用axios.get,替换为axios.delete
    const response = await axios.delete(`${API_URL}/${goalId}`, config);
    return response.data;
};

可选优化:登出逻辑的fulfilled回调中,可以同步dispatch goalSlice的reset action,清空本地存储的目标相关状态,避免登出后残留用户数据。

内容的提问来源于stack exchange,提问作者Ali Bin Naseer

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 12:31:10