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

为何React状态修改会改变原数组?如何避免默认数组被篡改

问题解析与解决方案

嘿,这个问题其实是JavaScript里引用类型的经典坑,我来给你掰扯清楚~

为什么const定义的数组会被修改?

首先得搞懂:const关键字只是保证变量本身的引用不会被改变——也就是说你不能给defaultButtons重新赋值成另一个数组,但它指向的数组(属于引用类型)内部的内容是完全可以修改的。

当你把defaultButtons直接赋值给state.buttons时,你并没有创建新数组,只是把同一个数组的引用传给了组件状态。这就像两个人共用同一个笔记本,不管谁在上面改内容,另一个人看到的都会是修改后的版本,哪怕你用const“锁”住了笔记本的名字,也拦不住里面的内容被改。

怎么避免修改原数组?

核心思路就是:给组件状态传一个原数组的副本,而不是原数组本身。这样状态和原数组就指向两个独立的内存空间,修改状态里的数组就不会影响到原数组了。

方法1:扩展运算符创建浅拷贝

这是最常用的方式,简单直观:

const defaultButtons = [{on: false},{on: false},{on: false}];
class Keyboard extends Component {
  // 创建原数组的浅拷贝作为初始状态
  state = { buttons: [...defaultButtons] }
  
  componentDidMount(){
    // 修改状态时直接替换为新数组,不会影响原数组
    this.setState({buttons: [{on: true},{on: true},{on: true}]})
    console.log(defaultButtons) // 现在会输出 [{on: false},{on: false},{on: false}] 啦!
  }
  
  render(){
    return(<div />)
  }
}

方法2:Array.from创建浅拷贝

效果和扩展运算符一致,写法不同而已:

state = { buttons: Array.from(defaultButtons) }

进阶:需要深拷贝的场景

上面的方法都是浅拷贝——如果数组里的元素是对象,拷贝后的数组里的对象还是和原数组里的对象共享同一个引用。如果你的场景需要修改对象内部属性,同时不想影响原数组里的对象,那就要用深拷贝:

比如用JSON.parse(JSON.stringify())(适合没有函数、Symbol等特殊类型的简单场景):

state = { buttons: JSON.parse(JSON.stringify(defaultButtons)) }

你也可以手写深拷贝函数,或者用第三方工具(比如Lodash的_.cloneDeep),不过普通场景下JSON方法足够用了。

修改状态的正确姿势

另外,在修改状态里的数组元素时,也要遵循React的不可变性原则,不要直接修改原状态数组,而是创建新的数组和对象:

// 示例:修改第一个按钮的on状态
this.setState(prevState => {
  // 先拷贝整个数组
  const newButtons = [...prevState.buttons];
  // 再拷贝要修改的对象,更新目标属性
  newButtons[0] = { ...newButtons[0], on: true };
  return { buttons: newButtons };
});

这样操作就完全不会影响到最初的defaultButtons数组啦~

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 08:35:57