You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Redux中不使用Immer如何通过展开运算符向嵌套state新增子数据

Redux原生实现嵌套Todo的ADD_SUBTODO更新逻辑

前置约定

你的ADD_SUBTODO action 的 payload 需要携带两个必要信息:

  • 要追加子待办的父任务ID:parentId
  • 完整的子待办项对象:subTodo(包含id、name、complete字段)

payload 参考结构:

{
  parentId: 1,
  subTodo: { id: 105, name: "subtask5", complete: false }
}

正确实现代码

遵循Redux不可变更新原则,用ES6展开运算符逐层做浅拷贝即可,不需要引入深拷贝:

export default function reducer(state = initialState, action) {
  switch (action.type) {
    case ADD_TODO:
      const newTodo = state.todos.concat(action.payload);
      return { ...state, todos: newTodo };

    case ADD_SUBTODO:
      const { parentId, subTodo } = action.payload;
      return {
        ...state,
        todos: state.todos.map(todo => {
          // 非目标父任务直接返回原引用,不做多余拷贝
          if (todo.id !== parentId) return todo;
          // 匹配到目标父任务,拷贝后更新subdata数组
          return {
            ...todo,
            subdata: [...todo.subdata, subTodo]
          };
        })
      };
    // 其他case逻辑
    default:
      return state;
  }
}

实现逻辑说明

不可变更新的核心要求是绝不直接修改原状态的引用,每一层被修改的对象/数组都要生成新的引用,未修改的内容保持原引用即可,兼顾性能和更新正确性:

  • 最外层通过...state生成新的根状态对象
  • 外层todos数组通过map生成新数组,没有修改原数组;未命中的父任务直接返回原对象,避免不必要的拷贝和组件重渲染
  • 命中的目标父任务通过...todo生成新的父任务对象,没有修改原父任务的属性
  • 父任务下的subdata数组通过展开运算符生成新数组,将新子待办追加到末尾,没有修改原subdata数组

避坑提醒

  • 禁止直接调用todo.subdata.push(subTodo)修改原数组,会导致状态引用未变化,Redux无法检测到更新,组件不触发重渲染
  • 不需要用JSON.parse(JSON.stringify(state))做全量深拷贝,性能差且会丢失特殊类型值,嵌套更新逐层浅拷贝是Redux官方推荐的原生写法
  • 不要对所有todo项都做全量拷贝,未修改的项保持原引用可以大幅提升渲染性能

内容的提问来源于stack exchange,提问作者ismbyc

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 13:51:30