Redux Toolkit已中止thunk为何不立即reject?如何处理loading状态
这不是Redux Toolkit的bug,属于预期行为。
原因说明
调用thunk的abort方法时,不会同步触发对应的rejected action:abort只是向thunk内部挂载的AbortSignal发送终止信号,需要等thunk的异步逻辑捕获到abort事件后,才会异步派发rejected action。而useEffect的清理函数执行完毕后,会同步执行下一轮的effect回调派发新的thunk,因此新thunk的pending action必然早于前一个thunk的rejected action触发,你观察到的action顺序是正常的。
解决方案
你可以选择以下任意一种方案适配你的业务场景:
方案1:请求计数器(适合需要统计所有未完成请求的场景)
不使用简单的布尔值控制加载状态,改用计数器统计未完成的请求数,只要存在未完成的请求就展示加载指示器:
// slice 里的state新增pendingCount字段,初始值为0 extraReducers: (builder) => { builder.addCase(asyncThunk.pending, (state) => { state.pendingCount += 1; }); builder.addCase(asyncThunk.fulfilled, (state) => { state.pendingCount = Math.max(0, state.pendingCount - 1); }); builder.addCase(asyncThunk.rejected, (state) => { state.pendingCount = Math.max(0, state.pendingCount - 1); }); } // 组件内取加载状态的逻辑改为 const isLoading = useSelector(state => state.yourSliceName.pendingCount > 0)
方案2:追踪最新请求ID(适合仅最后一次请求有效的场景)
利用createAsyncThunk自动生成的唯一请求ID,仅当返回结果属于当前最新的请求时才修改加载状态:
// slice 里的state新增activeRequestId字段,初始值为null extraReducers: (builder) => { builder.addCase(asyncThunk.pending, (state, action) => { state.isLoading = true; // 保存当前最新请求的ID state.activeRequestId = action.meta.requestId; }); builder.addCase(asyncThunk.fulfilled, (state, action) => { // 仅当返回结果属于最新请求时才关闭加载状态 if (state.activeRequestId === action.meta.requestId) { state.isLoading = false; } }); builder.addCase(asyncThunk.rejected, (state, action) => { // 仅当返回结果属于最新请求时才关闭加载状态 if (state.activeRequestId === action.meta.requestId) { state.isLoading = false; } }); }
两种方案都可以解决旧请求的rejected action提前覆盖加载状态的问题,你可以根据实际业务需求选择。
内容的提问来源于stack exchange,提问作者dprslt
相关产品推荐
相关产品推荐

