如何用单个Redux-Toolkit异步Thunk与extra reducer处理多API请求
复用Redux-Toolkit异步Thunk与Extra Reducer的方案
核心思路
通过给异步Thunk传入实体类型标识和API调用函数,让单个Thunk能处理不同资源的请求;同时编写通用的extra reducer生成函数,根据实体类型过滤action,避免多个slice误响应同一action导致的异常。
实现步骤
1. 创建通用异步Thunk
这个Thunk接收entityType(区分是公司还是客户)和fetchFn(实际的API请求函数)作为参数,请求成功/失败时把实体类型和数据/错误信息一起返回:
import { createAsyncThunk } from '@reduxjs/toolkit'; export const fetchEntity = createAsyncThunk( 'entities/fetch', async ({ entityType, fetchFn }, { rejectWithValue }) => { try { const response = await fetchFn(); return { entityType, data: response.data }; } catch (error) { return rejectWithValue({ entityType, error: error.response.data }); } } );
2. 编写通用Extra Reducer生成函数
生成对应实体类型的extra reducer逻辑,只处理与当前实体匹配的action:
export const createEntityExtraReducers = (entityType) => ({ pending: (state) => { state.loading = true; state.error = null; }, fulfilled: (state, action) => { if (action.payload.entityType === entityType) { state.loading = false; state.data = action.payload.data; } }, rejected: (state, action) => { if (action.payload.entityType === entityType) { state.loading = false; state.error = action.payload.error; } }, });
3. 在Slice中复用通用逻辑
Companies Slice
import { createSlice } from '@reduxjs/toolkit'; import { fetchEntity, createEntityExtraReducers } from './genericEntities'; const initialState = { data: [], loading: false, error: null, }; const companiesSlice = createSlice({ name: 'companies', initialState, reducers: {}, extraReducers: (builder) => { const reducers = createEntityExtraReducers('company'); builder .addCase(fetchEntity.pending, reducers.pending) .addCase(fetchEntity.fulfilled, reducers.fulfilled) .addCase(fetchEntity.rejected, reducers.rejected); }, }); export default companiesSlice.reducer;
Clients Slice
import { createSlice } from '@reduxjs/toolkit'; import { fetchEntity, createEntityExtraReducers } from './genericEntities'; const initialState = { data: [], loading: false, error: null, }; const clientSlice = createSlice({ name: 'clients', initialState, reducers: {}, extraReducers: (builder) => { const reducers = createEntityExtraReducers('client'); builder .addCase(fetchEntity.pending, reducers.pending) .addCase(fetchEntity.fulfilled, reducers.fulfilled) .addCase(fetchEntity.rejected, reducers.rejected); }, }); export default clientSlice.reducer;
4. 组件中调用Thunk
传入对应的实体类型和API请求函数即可:
// 获取公司列表 dispatch(fetchEntity({ entityType: 'company', fetchFn: () => api.get('/companies') })); // 获取客户列表 dispatch(fetchEntity({ entityType: 'client', fetchFn: () => api.get('/clients') }));
扩展优化
- 如果需要处理创建、更新、删除等更多异步操作,可以仿照
fetchEntity创建通用的createEntity、updateEntity等Thunk,同时扩展createEntityExtraReducers支持更多action类型。 - 可以把
initialState也封装成通用函数,进一步减少slice间的重复代码。
内容的提问来源于stack exchange,提问作者Mohan Dhila
相关产品推荐
相关产品推荐

