如何在Redux Toolkit的createSlice中减少代码重复?
解决Redux Toolkit中reducer代码重复的方案
针对你遇到的重复编写set/add/remove类型reducer的问题,可以通过抽象通用reducer生成函数的方式实现逻辑复用,新增字段时只需一行代码即可生成对应的三个reducer。
步骤1:编写通用reducer生成工具函数
这个函数接收目标字段名,自动生成对应的set/addTo/removeFrom三个reducer,同时通过TypeScript泛型保证类型安全:
import { PayloadAction } from '@reduxjs/toolkit'; // 辅助函数:将字段名首字母大写,用于生成规范的reducer名称 function capitalize(str: string): string { return str.charAt(0).toUpperCase() + str.slice(1); } /** * 为指定字段生成三个通用reducer:set、addTo、removeFrom * @param field 目标字段名(如'sliceObjectA') */ function createSliceObjectReducers<T extends { id: number }, K extends keyof T>(field: K) { return { // 设置指定id条目的字段完整数组 [`set${capitalize(field as string)}`]: (state: T[], action: PayloadAction<{ id: number; [key in K]: T[K] }>) => { const targetRow = state.find(row => row.id === action.payload.id); if (targetRow) { targetRow[field] = action.payload[field]; } }, // 向指定id条目的字段添加单个元素 [`addTo${capitalize(field as string)}`]: (state: T[], action: PayloadAction<{ id: number; [key in K]: T[K] extends Array<infer U> ? U : never }>) => { const targetRow = state.find(row => row.id === action.payload.id); if (targetRow) { (targetRow[field] as unknown as any[]).push(action.payload[field]); } }, // 从指定id条目的字段删除单个元素(按id匹配) [`removeFrom${capitalize(field as string)}`]: (state: T[], action: PayloadAction<{ id: number; [key in K]: (T[K] extends Array<infer U> ? U : never) & { id: number } }>) => { const targetRow = state.find(row => row.id === action.payload.id); if (targetRow) { targetRow[field] = (targetRow[field] as unknown as any[]).filter( (elem: { id: number }) => elem.id !== action.payload[field].id ) as T[K]; } } }; }
步骤2:在createSlice中复用该函数
直接通过扩展运算符将生成的reducer合并到slice的reducers对象中,新增字段时只需添加一行调用:
// 先修正你的类型定义(确保需要操作的字段是数组类型,否则push/filter会报错) interface SomeSliceType { id: number; sliceObjectA: SliceObjectA[]; sliceObjectB: SliceObjectB[]; sliceObjectC: SliceObjectC[]; sliceObjectD: unknown; } export const someSlice = createSlice({ name: "someSlice", initialState: [] as SomeSliceType[], reducers: { addSomeSlice: (state, action: PayloadAction<SomeSliceType>) => { state.push(action.payload); }, // 为sliceObjectA生成三个reducer ...createSliceObjectReducers<SomeSliceType, 'sliceObjectA'>('sliceObjectA'), // 为sliceObjectB生成三个reducer ...createSliceObjectReducers<SomeSliceType, 'sliceObjectB'>('sliceObjectB'), // 后续新增字段时,只需添加这一行即可 ...createSliceObjectReducers<SomeSliceType, 'sliceObjectC'>('sliceObjectC'), }, }); // 导出所有action creators(包括自动生成的) export const { addSomeSlice, setSliceObjectA, addToSliceObjectA, removeFromSliceObjectA, setSliceObjectB, addToSliceObjectB, removeFromSliceObjectB, setSliceObjectC, addToSliceObjectC, removeFromSliceObjectC } = someSlice.actions;
方案优势
- 彻底消除重复代码:通用逻辑只需定义一次,新增字段时无需复制粘贴重复代码。
- 类型安全:通过TypeScript泛型约束字段名和payload类型,避免类型错误。
- 扩展性强:后续无论新增多少个类似字段,都能通过一行代码生成对应的reducer。
内容的提问来源于stack exchange,提问作者Ericko
相关产品推荐
相关产品推荐

