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
相关产品推荐
相关产品推荐

