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

React Hooks+Axios取消请求时Redux loading状态更新顺序异常

问题诊断与解决方案

核心原因

请求被AbortController.abort()取消时,触发的Promise拒绝属于微任务,会在当前同步代码执行完成后才处理。筛选条件变更时,useEffect的实际执行流程为:

  1. 执行旧effect的清理函数(调用controller.abort())
  2. 立即执行新effect的回调(dispatch新请求的DRIVERS_API_CALL_START,将loading设为true)
  3. 同步代码执行完毕后,才处理旧请求的catch逻辑,dispatchDRIVERS_API_CALL_FAIL将loading设为false

最终导致loading被错误重置为false,加载指示器无法正常显示。

解决方案一:忽略请求取消的错误(推荐)

请求取消是用户主动触发的预期行为,不应算作API调用失败。在catch块中判断错误类型,跳过AbortError的错误处理即可:

修改getDrivers中的catch逻辑:

.catch((error) => {
    // 跳过请求取消的错误,不触发失败动作
    if (error.name === 'AbortError') {
        return;
    }
    const actionType = 'getDrivers';
    throw parseError(dispatch, driversApiCallFail, error, actionType);
});

同时,需要在请求成功的动作中补充设置loading为false:

case actionTypes.GET_DRIVERS_SUCCESS:
    draft.loading = false;
    draft.data = action.payload;
    break;

解决方案二:通过请求计数维护loading状态

如果需要保留取消请求的错误处理,可以通过维护请求计数,确保只有当所有pending请求都完成时才将loading设为false:

  1. 更新初始状态:
const initialState = {
    loading: false,
    requestCount: 0,
    error: null,
    data: []
};
  1. 修改reducer中的动作处理:
case actionTypes.DRIVERS_API_CALL_START:
    draft.loading = true;
    draft.requestCount += 1;
    break;
case actionTypes.DRIVERS_API_CALL_FAIL:
    draft.requestCount -= 1;
    // 仅当没有pending请求时才关闭loading
    if (draft.requestCount === 0) {
        draft.loading = false;
    }
    draft.error = {
        apiCall: action.payload.apiCall,
        message: action.payload.message
    };
    break;
case actionTypes.GET_DRIVERS_SUCCESS:
    draft.requestCount -= 1;
    if (draft.requestCount === 0) {
        draft.loading = false;
    }
    draft.data = action.payload;
    break;

这样即使旧请求的失败动作晚于新请求的开始动作,也不会错误地将loading重置为false,直到所有请求都完成。

内容的提问来源于stack exchange,提问作者Mihai Stan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 02:40:24