如何将createAsyncThunk的结果传递给自定义Redux中间件?
我的自定义Redux中间件需要依赖createAsyncThunk生成的fulfilled动作结果,但目前的问题是:中间件处于动作与reducer之间,只能通过getState()访问状态,而createAsyncThunk带来的状态更新要等reducer处理完动作后才会生效,此时中间件拿到的还是旧状态。

用户切片代码
// 获取用户列表 export const getUsers = createAsyncThunk( 'users/getUsers', async (arg, { rejectWithValue }) => { try { const response = await axios.get('users'); return response.data; } catch (error) { return rejectWithValue(error.response.data); } }, ); // 初始状态 const initialState = { users: [], isLoading: false, hasError: false, errorMessage: '', }; const usersSlice = createSlice({ name: 'users', initialState, extraReducers: builder => { builder .addCase(getUsers.pending, (state, action) => { state.isLoading = true; state.hasError = false; state.errorMessage = false; }) .addCase(getUsers.fulfilled, (state, action) => { state.users = action.payload.users; state.isLoading = false; state.hasError = false; }) .addCase(getUsers.rejected, (state, action) => { state.errorMessage = action.payload.message; state.isLoading = false; state.hasError = true; }) }, });
自定义中间件代码
const customMiddleware = store => next => action => { // 这里拿到的是旧状态,因为reducer还没处理动作 const users = store.getState().users; // 业务逻辑 .................................... return next(action); };
我理解createAsyncThunk本身是处理异步逻辑的中间件,Redux存在中间件链:Action => middleware A => middleware B => middleware C => Reducer => Store
我想要在middleware B中访问middleware A(也就是createAsyncThunk)的执行结果,实现中间件之间的联动。在Redux里有没有办法做到?
补充细节
我用这个中间件通过Socket IO和Laravel Echo建立私有WebSocket连接,需要用到createAsyncThunk成功响应后返回的一个ID,用这个ID拼接私有频道名称:
echo.private(`transport.${id}`).listen(...);
1. 直接监听fulfilled动作,从动作payload取数据
不需要依赖getState(),中间件可以直接判断当前动作是否是getUsers.fulfilled,然后从action.payload里拿到需要的ID——createAsyncThunk的fulfilled动作payload就是异步请求返回的数据,这比等reducer更新状态更直接可靠。
修改后的中间件示例:
const customMiddleware = store => next => action => { // 监听getUsers的fulfilled动作 if (getUsers.fulfilled.match(action)) { // 从动作payload里直接提取需要的ID const targetId = action.payload.targetId; // 假设payload包含该ID // 建立WebSocket连接 echo.private(`transport.${targetId}`).listen('SomeEvent', (e) => { // 处理WebSocket事件,可通过dispatch更新状态 store.dispatch(someAction(e.data)); }); } return next(action); };
2. 调整中间件执行顺序
Redux中间件的执行顺序由configureStore中传入的数组顺序决定:将自定义中间件放在thunk中间件之后,这样createAsyncThunk完成异步请求并发出fulfilled动作时,会先经过你的自定义中间件,再到达reducer。同样,这里依然推荐直接从action.payload取数据,而非依赖getState()的旧状态。
配置Store示例:
import { configureStore } from '@reduxjs/toolkit'; import thunk from 'redux-thunk'; import customMiddleware from './customMiddleware'; import usersReducer from './usersSlice'; export const store = configureStore({ reducer: { users: usersReducer, }, middleware: [thunk, customMiddleware], // 先执行thunk,再执行自定义中间件 });
3. 在createAsyncThunk内部直接处理WebSocket逻辑
如果WebSocket连接逻辑与该异步请求强绑定,完全可以把建立连接的代码放到createAsyncThunk的成功回调里,无需通过中间件:
export const getUsers = createAsyncThunk( 'users/getUsers', async (arg, { rejectWithValue, dispatch }) => { try { const response = await axios.get('users'); const { users, targetId } = response.data; // 直接建立WebSocket连接 echo.private(`transport.${targetId}`).listen('SomeEvent', (e) => { dispatch(someAction(e.data)); }); return response.data; } catch (error) { return rejectWithValue(error.response.data); } }, );
这种方式更直接,避免了中间件的依赖问题,适合逻辑耦合度高的场景。
内容的提问来源于stack exchange,提问作者Nima Zarei

