如何在数组中嵌套Redux Reducer?多层级状态管理求助
解决Redux嵌套Reducer的组合问题
我明白你现在的困扰——在Redux里处理嵌套的routines和days状态时,不知道怎么正确组合reducer来实现给指定routine添加day的功能。先来看你现有代码里的核心问题:
现有代码的问题
在routineReducer的ADD_ROUTINE case中,你把days赋值为dayReducer函数,这是错误的——reducer是用来处理状态更新的函数,而不是状态本身。我们需要的是初始的days状态(比如空数组)。
修正方案:嵌套状态的正确更新方式
我们需要让routineReducer能够定位到目标routine,然后调用dayReducer来更新该routine的days数组。以下是分步实现:
1. 定义Action类型(先明确操作类型)
const ADD_ROUTINE = 'ADD_ROUTINE'; const ADD_ROUTINE_DAY = 'ADD_ROUTINE_DAY';
2. 完善dayReducer
保持它的职责单一,只处理days数组的更新:
function dayReducer(state = [], action) { switch (action.type) { case ADD_ROUTINE_DAY: return [ ...state, { dayName: action.dayName, exercises: [] // 和你的示例状态保持一致,初始化为空练习数组 } ]; default: return state; } }
3. 修正routineReducer
现在让它同时处理添加routine和给指定routine添加day的逻辑:
function routineReducer(state = [], action) { switch (action.type) { case ADD_ROUTINE: return [ ...state, { id: Date.now().toString(), // 生成唯一ID(推荐用uuid库更可靠) name: action.name, days: [] // 初始化为空数组,而不是reducer函数 } ]; case ADD_ROUTINE_DAY: // 遍历找到目标routine,更新它的days数组 return state.map(routine => { if (routine.id === action.routineId) { // 调用dayReducer更新当前routine的days状态 return { ...routine, days: dayReducer(routine.days, action) }; } return routine; }); default: return state; } }
4. 保持Reducer组合方式不变
const fitnessApp = combineReducers({ routines: routineReducer, routing });
5. 创建Action Creators(方便触发操作)
// 添加新routine export const addRoutine = (name) => ({ type: ADD_ROUTINE, name }); // 给指定routine添加day export const addRoutineDay = (routineId, dayName) => ({ type: ADD_ROUTINE_DAY, routineId, dayName });
优化建议:用Immer简化不可变更新
如果觉得手动处理不可变状态(展开运算符、map)太繁琐,可以用immer库来简化代码,它允许你直接“修改”状态,内部会帮你生成不可变的新状态:
import produce from 'immer'; import { v4 as uuidv4 } from 'uuid'; // 推荐用uuid生成唯一ID function routineReducer(state = [], action) { return produce(state, draft => { switch (action.type) { case ADD_ROUTINE: draft.push({ id: uuidv4(), name: action.name, days: [] }); break; case ADD_ROUTINE_DAY: const targetRoutine = draft.find(r => r.id === action.routineId); if (targetRoutine) { // 直接调用dayReducer更新days,或者用immer直接push targetRoutine.days = dayReducer(targetRoutine.days, action); } break; } }); }
关键要点总结
- 不要把Reducer作为状态值:初始状态应该是对应的数据结构(比如空数组),Reducer是用来处理状态更新的函数。
- 保持不可变性:Redux要求状态是不可变的,所以更新嵌套状态时要通过
map、展开运算符或者Immer来创建新的数组/对象。 - 用唯一ID标识列表项:避免依赖数组索引来定位routine,因为数组顺序变化会导致索引失效,用唯一ID更可靠。
内容的提问来源于stack exchange,提问作者Jordan Coil
相关产品推荐
相关产品推荐

