如何在Reducer中正确操作状态?嵌套数组删除场景求解
正确实现Reducer中移除已回答问题的逻辑
嘿,我来帮你搞定这个Reducer的问题!你现在的写法有个核心问题:直接用splice修改了原state,这违反了Redux的不可变更新原则——Reducer必须是纯函数,不能改动原状态,得返回全新的状态对象才行。下面给你两种靠谱的实现方式:
方法一:原生JavaScript不可变更新(无需额外库)
首先要确保你的action能传递动态的索引(比如要操作的questionGroup索引和要移除的question索引),然后通过扩展运算符和数组方法实现无修改的更新:
case ANSWER_QUESTION: // 从action.payload里拿到动态的索引(建议你把这些参数放在action里传进来) const { groupIndex, questionIndex } = action.payload; // 1. 先复制外层的questionGroups数组,避免修改原数组 const updatedQuestionGroups = [...state.questionGroups]; // 2. 复制目标分组对象,因为不能直接修改原分组 const targetGroup = updatedQuestionGroups[groupIndex]; const updatedGroup = { ...targetGroup, // 3. 复制questions数组,并移除指定索引的问题(用filter或slice都可以) // 方式A:filter过滤掉目标索引的元素 questions: targetGroup.questions.filter((_, idx) => idx !== questionIndex), // 方式B:用slice拼接数组(效果和filter一致) // questions: [...targetGroup.questions.slice(0, questionIndex), ...targetGroup.questions.slice(questionIndex + 1)] }; // 4. 更新分组数组里的对应项 updatedQuestionGroups[groupIndex] = updatedGroup; // 返回全新的state对象 return { ...state, questionGroups: updatedQuestionGroups };
方法二:用Immer简化嵌套更新(推荐复杂场景)
如果你的状态嵌套比较深,原生写法会很繁琐,用Immer库可以让你像“直接修改”状态一样写代码,它会自动帮你生成不可变的新状态:
首先安装Immer:
npm install immer # 或 yarn add immer
然后在Reducer里使用:
import { produce } from 'immer'; // ...其他Reducer代码 case ANSWER_QUESTION: const { groupIndex, questionIndex } = action.payload; // 用produce包裹,直接修改draft(草稿)即可 return produce(state, draft => { draft.questionGroups[groupIndex].questions.splice(questionIndex, 1); });
关键说明
- 为什么原代码不行?
splice是会修改原数组的方法,而Redux依赖状态的引用变化来触发组件更新,直接修改原state会导致React无法检测到状态变化,组件不会重新渲染。 - 不管用哪种方法,核心都是不修改原状态,只生成新的状态对象/数组。
内容的提问来源于stack exchange,提问作者Aleski
相关产品推荐
相关产品推荐

