如果我使用传播运算符,为什么状态会发生变化?

时间:2019-05-04 22:35:22

标签: reactjs state

我有正在jsfiddle上测试的这段代码

onVote = (dir, index) => {        
    console.log(this.state)

    const products = [...this.state.products]           
    products[index].votes = dir ? products[index].votes + 1 : products[index].votes - 1

    console.log(this.state.products[index].votes)
    // this.setState({products})
  };

https://jsfiddle.net/hkL3wug7/2/

但是,即使我没有设置“状态”,控制台日志也会显示每次单击加号和减号时状态都会改变。

我所做的与本文https://medium.com/@giltayar/immutably-setting-a-value-in-a-js-array-or-how-an-array-is-also-an-object-55337f4d6702

相同
const newState = [...state] // clone the array
      newState[action.index].done = true
      return newState

据我了解

(这不是另一个问题的重复,我不是在寻求有效的方法)

2 个答案:

答案 0 :(得分:3)

正如@Carcigenicate所说,您已经创建了数组的浅表副本,这意味着您有一个指向原始对象中相同对象的新数组。

为避免变异原始对象,您还需要创建一个您想要变异的对象的副本,例如:

// Shallow copy of the array
const products = [...this.state.products];

// Shallow copy of the object within the array
const updatedProduct = { ...products[index] };

// Update the copy of the object
updatedProduct.votes = dir ? updatedProduct.votes + 1 : updatedProduct.votes - 1;

// Replace the object with the updated copy
products[index] = updatedProduct;

答案 1 :(得分:1)

正如注释中提到的@Carcigenicate,使用散布运算符将创建数组的浅表副本。这给您带来了问题,因为数组的扩展版本包含Object,这些引用是通过引用传递的。因此,即使您的局部变量productsthis.state.products的新副本,它们都包含对相同Object的引用。

要实现您要执行的操作,您必须在this.state.products中克隆对象。一种可行的方法是使用Object.assign并将const products = [...this.state.products]替换为:

const products = [
    Object.assign({}, this.state.products.Orange),
    Object.assign({}, this.state.products.Apples),
    Object.assign({}, this.state.products.Bananas)
]