Question regarding handleIncrement() method in the Mastering React lesson

In Lecture 10-Removing the Local State of the ‘Composing Components’ section of Mastering React, Mosh refactors his code to move the function definition of handleIncrement() from the Counter component into the Counters component. The newly-created method in Counters follows. I starred the line of code in this method that is bothering me below:

    handleIncrement = counter => {

     const counters = [...this.state.counters];  
     const index = counters.indexOf(counter); 
     counters[index] = {...counter};  ***
     counters[index].value++;
     this.setState({counters});
     }

***counters[index] = {...counter}; This is where I’m confused. It seems that all this is doing is spreading the contents of the raised counter object and assigning them to the index of the array that it already occupied. Since the attributes of the counter object aren’t being modified by the Counter component, shouldn’t we be able to assume that the value of counters[index] is already equal to {…counter}? Furthermore, I understand the idea that we don’t want to modify the state directly, but since we are working with a cloned array and not the state already, I don’t see how this line of code is accomplishing anything along those lines. In other words, what purpose is this line of code actually serving? I was able to comment it out and run the app with apparently full functionality, so I’m wondering if this line is useful in more complex applications for some reason that I am not grasping.

Spreading creates shallow copies. So after counters = [...this.state.counters] we have a new array that is not part of the state but the elements inside it are still the same as in this.state.counters. They are references (pointers) referencing objects in the state. If we modified any of these elements we would be modifing the state.

To avoid this we need to make a copy of the element we want to change.

You often don’t see effects of modifying the state directly immediately. As your app grows more complex you will see bugs that are very hard to find. That’s why Mosh emphasizes this so much.

1 Like

So from what I have gathered, cloning by spreading will make a deep copy of a simple array, but if there are nested components, then those will remain as pointers. So, does […this.state.counters] create a shallow copy because there are nested objects within the array?

Spreading always works the same. It iterates over the elements of the object to spread and inserts them into the expression. If the elements are primitives you are safe, if they are objects they might still point to values in the state.

1 Like