嵌套Redux Reducer执行ADD_TODO后状态返回null问题求助
解决嵌套Redux Reducer + Reselect下ADD_TODO后的异常状态问题
我帮你梳理下问题所在,大概率是你的嵌套Reducer职责划分和状态更新逻辑没对齐,才导致ADD_TODO触发后出现了{0: null, 1: null}这种异常状态。咱们一步步拆解修复:
1. 明确Reducer的职责划分
你现在的代码里有一个todo reducer,但看起来它的职责和todos列表的管理混在一起了。正确的嵌套结构应该是:
- 单个todo的reducer:只负责处理单个todo对象的状态变化(比如创建、切换完成状态)
- todos列表的reducer:负责管理整个todo数组,调用单个todo reducer来生成/更新列表项
修正单个todo的Reducer
// 单个todo的reducer,仅处理单个todo的状态 const todo = (state, action) => { switch (action.type) { case 'ADD_TODO': // 补全你截断的completed字段,生成标准todo对象 return { id: action.id, text: action.text, completed: false }; // 可选:添加其他todo相关的action处理,比如切换完成状态 case 'TOGGLE_TODO': if (state.id !== action.id) return state; return { ...state, completed: !state.completed }; default: return state; } };
修正todos列表的Reducer
这个reducer负责维护todo数组,调用上面的单个todo reducer来处理新增/更新:
// 管理todo列表的reducer const todos = (state = [], action) => { switch (action.type) { case 'ADD_TODO': // 调用单个todo reducer生成新todo,再添加到数组末尾 return [...state, todo(undefined, action)]; case 'TOGGLE_TODO': // 遍历数组,对匹配的todo执行状态更新 return state.map(t => todo(t, action)); default: return state; } };
组合根Reducer
把todos和visibilityFilter组合成根reducer,确保状态结构和初始状态匹配:
import { combineReducers } from 'redux'; import { fromJS } from 'immutable'; // 单独处理visibilityFilter的reducer const visibilityFilter = (state = 'SHOW_ALL', action) => { switch (action.type) { case 'SET_VISIBILITY_FILTER': return action.filter; default: return state; } }; // 组合所有子reducer const rootReducer = combineReducers({ todos, visibilityFilter }); // 注意:如果坚持用Immutable.js的fromJS初始化状态, // 要确保todos reducer也处理Immutable数组(比如用state.push()而非展开运算符), // 更推荐用普通对象配合展开运算符/immer,降低复杂度
2. 修正Reselect选择器的逻辑
你的makeSelectTodos需要正确匹配最终的状态结构。如果根状态直接包含todos字段,选择器应该这么写:
// containers/HomePage/selectors.js import { createSelector } from 'reselect'; // 先从根状态提取todos const selectTodos = state => state.todos; // 创建记忆化选择器 const makeSelectTodos = createSelector( selectTodos, // 如果是普通数组直接返回;如果是Immutable数组,按需用toJS()转换成普通对象 todos => todos ); export { makeSelectTodos };
3. 为什么会出现{0: null, 1: null}?
这种异常状态大概率是因为:
- 你错误地把单个
todoreducer直接当成了todos列表的reducer,导致ADD_TODO时返回了单个对象,Redux把这个对象当成了数组的“索引键值对”,未被覆盖的索引就变成了null - 或者你使用Immutable.js时,没有正确处理数组的更新操作,导致Immutable数组被意外转换成了普通对象
按照上面的步骤调整后,ADD_TODO触发后状态应该会变成{ todos: [{id:1, text:'xxx', completed:false}, ...], visibilityFilter: 'SHOW_ALL' }的正常结构。
内容的提问来源于stack exchange,提问作者Erdal SATIK
相关产品推荐
相关产品推荐

