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

为什么React中这种非突变的状态更新方式能够正常生效?

原理说明

你的猜测是正确的,这个写法的运行逻辑完全符合JavaScript的引用类型规则:

  • 第一行const newTodoList = [...todos]做的是数组浅拷贝:仅创建了一个新的数组实例,数组内部存储的所有todo对象依旧和原todos数组里的对象指向同一块内存空间,没有生成新的对象副本。
  • 第二行const todo = newTodoList.find(todo => todo.id === id)获取到的todo变量,是指向newTodoList中对应id的对象的引用,不是独立的新对象。这里const声明的作用仅限制todo变量不能被重新赋值为其他值(比如不能再让它指向另一个对象),但完全允许修改它指向的对象的自身属性。
  • 所以你修改todo.complete时,本质就是直接修改newTodoList里对应对象的属性,二者指向同一份数据,不存在额外的同步步骤。
  • 最后将newTodoList传入setTodos,React检测到数组引用发生了变化,就会触发组件重渲染,读取到更新后的complete属性值。

写法风险提示

该写法虽然能正常运行,但不符合React的不可变更新最佳实践:由于你直接修改了数组内的原有对象属性,若项目中存在依赖todo对象引用变化的逻辑(比如用React.memo包裹子组件,且将todo对象作为props传入),会出现子组件无法感知到属性变化、不触发重渲染的问题。更规范的写法如下:

function toggleTodo(id){
  const newTodoList = todos.map(todo => {
    if(todo.id === id) {
      // 生成全新的对象,保证引用变化能被所有依赖逻辑检测到
      return {...todo, complete: !todo.complete}
    }
    return todo
  })
  setTodos(newTodoList)
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 18:45:03