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

