Redux Toolkit 深度嵌套平展数据调用init方法未更新状态问题求助
问题成因
Redux 基于不可变数据原则设计,状态更新的判断逻辑为浅对比引用地址,你当前的写法属于直接修改原状态的引用对象,无法被 Redux 检测到变化,因此不会触发更新:
- 通过
flatMap检索得到的task是原 state 树中对象的直接引用,调用init方法是直接修改该引用指向的原对象属性,没有生成新的对象引用 - Redux 要求 reducer 每次返回全新的状态对象,所有被修改的层级都需要更新引用,浅比较才会判定状态发生变化
解决方法
方案1:手动逐层更新引用
按照 state 的嵌套层级,逐层生成新的数组/对象引用,仅修改目标节点,未修改的节点保留原引用以优化性能:
// Redux reducer 示例代码 return { ...state, data: state.data.map(project => { // 不包含目标task的项目直接返回原引用 if (!project.hierarchyLines.some(h => h?.tasks?.some(t => t.id === payload.id))) { return project; } return { ...project, hierarchyLines: project.hierarchyLines.map(hLine => { if (!hLine?.tasks?.some(t => t.id === payload.id)) { return hLine; } return { ...hLine, tasks: hLine.tasks.map(task => { if (task.id !== payload.id) return task; // 生成全新的task实例,避免修改原引用 const newTask = new Task(); newTask.init(payload); return newTask; }) }; }) }; }) };
方案2:使用 Immer 简化不可变更新
如果嵌套层级较深,手动逐层展开代码冗余度高,可以引入 Immer 库简化逻辑,直接修改 draft 代理对象即可自动生成全新的不可变状态:
import { produce } from 'immer'; const yourReducer = produce((draft, action) => { const { payload } = action; // 写法和你原有逻辑几乎一致,immer会自动处理引用更新 const tasks = draft.data.flatMap(p => p.hierarchyLines).flatMap(h => h?.tasks); const task = tasks.find(t => t?.id === payload.id); task?.init(payload); }, initialState);
注意事项
- 禁止直接修改原 state 中的任何引用对象,所有更新操作都要对应生成新的引用
- 如果用 class 实例作为 state 存储结构,更新时必须生成全新的实例,不要修改原实例的属性
内容的提问来源于stack exchange,提问作者supermar10
相关产品推荐
相关产品推荐

