1

I have this code that I am testing on 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/

However, even though I am not setting State, the console log shows that the state is changes every time I click on the plus and minus signs.

I did the same as in this article 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

as far as I understand

(it is not duplicate of the other question, I am not asking for an efficient way)

user3808307
  • 2,270
  • 9
  • 45
  • 99
  • 2
    That's a shallow copy of the list structure. That doesn't make copies of the elements it contains. You'll need to make copies of them somehow. – Carcigenicate May 04 '19 at 22:39
  • Possible duplicate of [What is the most efficient way to deep clone an object in JavaScript?](https://stackoverflow.com/questions/122102/what-is-the-most-efficient-way-to-deep-clone-an-object-in-javascript) – Carcigenicate May 04 '19 at 22:39

2 Answers2

6

As @Carcigenicate mentioned, you have created a shallow copy of the array which means you have a new array pointing to the same objects in the original.

To avoid mutating the original object, you will need to also create a copy of the one you would like to mutate, e.g.:

// 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;
smashed-potatoes
  • 2,068
  • 1
  • 13
  • 17
2

As @Carcigenicate mentioned in the comment, using the spread operator creates a shallow copy of the array. This is creating a problem for you because the expanded version of the array contains Objects which are passed by reference. So even though your local variable products is a new copy of this.state.products, they both contain references to the same Objects.

To achieve what you are trying to do, you would have to clone the objects in this.state.products. One possible way to do this is using Object.assign and replace your const products = [...this.state.products] with:

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