0

In the following code, I am not understanding why we need the following line, if counters is already equal to the state. What is the doing? Can I delete the line?

counters[index] = { ...counters[index] };

here is the whole thing.

class App extends Component {
      state = {
        counters: [
          { id: 1, value: 0 },
          { id: 2, value: 0 },
          { id: 3, value: 0 },
          { id: 4, value: 0 }
        ]
      };

      handleIncrement = counter => {
        const counters = [...this.state.counters];
        const index = counters.indexOf(counter);
        counters[index] = { ...counters[index] };
        counters[index].value++;
        this.setState({ counters });
      };
Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
Chucky787
  • 3
  • 4
  • 1
    It's done to avoid mutating state. The first round of destructuring copies the outer array, but in order to safely update the nested object without mutation, it needs to be copied as well. – Brian Thompson May 22 '20 at 19:43
  • Thanks, I sort of understand, but not exactly. I remember in some tutorials before people using .slice(). Would that solve the same problem so I do not need that line? Maybe if I make the first counters= [...this.state.counters.slice()], that way it is complete copy and nothing to do with the state? I am still a big foggy. – Chucky787 May 22 '20 at 19:50
  • The issue is due to the fact that objects and arrays are stored in variables as *references*. Copying the outer array doesn't break the reference to the inner object. I wrote a pretty long explanation in [this answer](https://stackoverflow.com/questions/59738516/component-wont-update-when-a-redux-state-change-occurs/59738588#59738588) about why, and how make nested copies if you'd like to read through that it might make things clearer (starting at Explanation). – Brian Thompson May 22 '20 at 19:56
  • Read your explanation, and after thinking for while, think I wrapped my head around it.. so adding ... before the array name has the effect of making a copy of that array (but just at the layer?), so the first time it creates a copy of counters (so counters has a unique reference), but the inside of it all still refers to the original state values (not unique reference), therefore when I set the inside values I want to set it not directly to counters[index] as this will end up mutating state when we do counters[index].value++ as it is still referring to state? Do I have the thinking straight? – Chucky787 May 22 '20 at 20:14
  • Yeah it sounds like you've got it! – Brian Thompson May 22 '20 at 20:15
  • Was getting so frustrated, so happy to finally understand, appreciate your help! – Chucky787 May 22 '20 at 20:19

1 Answers1

0

The original intent seems to be to create a new object that looks identical to the original one (copies all the properties over), but this is done to avoid mutating the original state in place.

I suspect it would appear to "work fine" without this line, but React state is intended to be immutable.

E.g. see: https://flaviocopes.com/react-immutability/

Chase
  • 3,028
  • 14
  • 15
  • I don't understand what that line is doing. Can't wrap my head around it...isn't it just like having an array[1,2,3] and saying array[0]=array[0]? What does this accomplish. Also doesn't the first line that initializes the counters array just copy all of what is in the state, therefore will not mutate the state until the last line? – Chucky787 May 22 '20 at 19:58