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

ReactJS中赋值state到变量时为何需用方括号包裹?

现象原因

你最初的代码无法生效,核心是违反了React的state不可变更新规则:

  • JS中数组属于引用类型,let pastTodos = this.state.pastTodos; 是引用赋值,变量pastTodos直接指向state中原有数组的内存地址,后续调用push方法是直接修改了state里的原数组。
  • React触发重渲染的判断逻辑是对比新旧state的引用是否变化,你直接修改原数组的话,新旧state指向的是同一个内存地址,React会判定状态没有更新,自然不会触发界面重渲染,功能看起来就失效了。
你当前修改方案的问题

你改成let pastTodos = [this.state.pastTodos];后看起来功能正常,其实是误判:

  • 这行代码的作用是创建一个新数组,把原state里的pastTodos整个数组作为新数组的第一个元素,本质生成的是嵌套结构[原pastTodos数组, 新currentTodo],根本不是你想要的一维待办列表。
  • 你现在觉得功能生效,只是因为当前代码还没写渲染pastTodos列表的逻辑,只看到输入框内容被清空,就误以为添加逻辑正常。等你后续遍历pastTodos渲染列表时,会直接拿到嵌套数组,出现渲染错误。
最优实现方式

正确的写法要满足两个要求:不直接修改原state数组、生成的新数组是一维结构,推荐用最简洁的展开运算符实现:

handleClick(e) {
  e.preventDefault();
  this.setState(prevState => ({
    // 浅拷贝原有待办数组,追加新待办项,同时清空输入框
    pastTodos: [...prevState.pastTodos, prevState.currentTodo],
    currentTodo: ""
  }));
}

这里给setState传入更新函数而不是直接传对象,是因为setState本身是异步的,用函数参数拿prevState可以避免拿到过期的状态值,是最严谨的写法。
如果不习惯展开运算符,也可以用concat实现等价效果,concat本身会返回新数组,不会修改原数组:

handleClick(e) {
  e.preventDefault();
  const pastTodos = this.state.pastTodos.concat(this.state.currentTodo);
  this.setState({ pastTodos, currentTodo: "" });
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 13:19:05