Redux Toolkit中thunk中间件如何返回Promise实现异步后跳转
问题根源
- thunk内部catch块直接return错误对象,相当于把所有请求异常内部消化,thunk永远不会进入rejected状态,外层拿不到错误
- 调用
dispatch(addExpense(form))后没有等待异步逻辑执行完就直接跑路由跳转代码,自然会出现请求未完成就跳页的情况 - Redux Toolkit的
createAsyncThunk默认dispatch后返回的Promise不会抛出rejected错误,需要手动调用unwrap拆包才能正常捕获异常
具体修改步骤
1. 修正thunk定义,不要吞掉错误
用createAsyncThunk自带的rejectWithValue工具处理错误返回,不要自己在catch里返回混合成功/失败的结构:
import { createAsyncThunk } from "@reduxjs/toolkit"; import axios from "../../../../src/axios"; export const addExpense = createAsyncThunk( "expense/addExpense", async (expense, { rejectWithValue }) => { try { const res = await axios.post("/expense", expense); return res.data.expense; } catch (err) { // 把后端返回的错误信息传到rejected action中 return rejectWithValue(err.response.data.message); } } );
2. 同步修改extraReducers状态逻辑
适配新的thunk返回结构,每次发请求前清空旧错误:
[addExpense.pending]: (state) => { state.creatingExpense = true; state.error = null; }, [addExpense.fulfilled]: (state, action) => { const expense = action.payload; state.creatingExpense = false; if (state.expense && state.currentMonth === expense.month) { state.expense = [...state.expense, expense]; } }, [addExpense.rejected]: (state, action) => { state.creatingExpense = false; state.error = action.payload || action.error.message; },
3. 修改提交逻辑,等待请求完成再跳转
调用unwrap()拆包Promise,请求成功后再执行路由跳转,失败时进catch分支处理错误:
const handleSubmit = async (e) => { e.preventDefault(); const year = form.date.split("-")[0]; const month = form.date.split("-")[1]; try { // 等待异步请求完成 await dispatch(addExpense(form)).unwrap(); // 只有请求成功才会走到这里执行跳转 navigate(`/year/${year}/${months[month - 1]}`); } catch (err) { // 请求失败会进入这里,可自由处理错误 console.log(err); alert(err); } };
关键提示:如果不用async/await,用链式调用写法也可以,只要记得加.unwrap()就行,示例:
dispatch(addExpense(form)) .unwrap() .then(() => { navigate(`/year/${year}/${months[month - 1]}`); }) .catch((err) => { console.log(err); });
内容的提问来源于stack exchange,提问作者Deep Shah
相关产品推荐
相关产品推荐

