1

I'm studying a React course at a point where the instructor is explaining about updating states and I cannot understand how those two snippets are really different internally, please see in the codepen links below:

Updates the state directly snippet

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

  handleIncrement = counter => {
    const updatedCounters = [...this.state.counters];
    updatedCounters[0].value++;
  };
}

Updates the state indirectly then save snippet

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

  handleIncrement = counter => {
    const updatedCounters = [...this.state.counters];
    const index = updatedCounters.indexOf(counter);
    updatedCounters[index] = {...counter};
    updatedCounters[index].value++;
    this.setState({ counters: updatedCounters });
  };
}

In this lecture, the instructor explains that the first snippet does update the state directly. So my question is, if the first example, as the instructor says, updates the state directly, the only thing that prevents the second snippet from updating the state directly is the line below?:

updatedCounters[index] = {...counter};

If that is true, how does it works?

  • 2
    [The difference is immutability.](https://stackoverflow.com/q/37755997/1218980) – Emile Bergeron Nov 26 '19 at 00:20
  • Also, the line is wrong, so it's understandable that you're having difficulty grasping it. – Emile Bergeron Nov 26 '19 at 00:21
  • Possible duplicate of [Whats the best way to update an object in an array in ReactJS?](https://stackoverflow.com/questions/28121272/whats-the-best-way-to-update-an-object-in-an-array-in-reactjs) – Emile Bergeron Nov 26 '19 at 00:22
  • Hey @EmileBergeron, so you're saying it's just because the first snippet is missing the this.setState? Which line is wrong btw? – Gabriel Oliveira Nov 26 '19 at 00:25
  • So @EmileBergeron, I had seen that post before and I knew I had to use setState, I guess my question would make more sense if I could show the video i was watching, but I cannot due copyright. But, visiting this link one more time made me read the entire discussion and now I understand a few things more clearly. Thanks it helped. – Gabriel Oliveira Nov 26 '19 at 00:33
  • The line that is wrong is `udatedCounters[index] = [...counter];`, you fixed it in the snippet above, but not in the last snippet. – Emile Bergeron Nov 26 '19 at 00:55

3 Answers3

2

In the first example, updatedCounters is a copy of this.state.counters, but the items inside that copy are references to the exact same objects in the original. This might be analogous to moving some books to a new box. The container changed, but the contents did not. In the second example, you don't mutate the selected counter, you copy the counter and then mutate that copy.

Michelle Tilley
  • 157,729
  • 40
  • 374
  • 311
1

When it comes to state modifications in React, You always need to remember about the fact that the state can not be mutated. Well , technically You can do that but it's a bad practice and it's a antipattern. You always want to make a copy of the state and modify the copy instead of the original state object. Why ? It really improves the performance of the application and that's React's huge advantage. It's called immutability. You might also ask .. "How does this approach improve the performance?" Well, basically, thanks to immutability pattern, react does not have to check the entire state object. Instead of that, React does a simple reference comparison. If the old state isn't referencing the same obj. in memory -> we know that the state has changed. Always try to use .setState() to avoid mutating state in a wrong way and that's what you do here:

handleIncrement = counter => {
    const updatedCounters = [...this.state.counters];
    updatedCounters[0].value++;
  };
AdamKniec
  • 1,607
  • 9
  • 25
0

Basically the answer to my own question is that, if you do not call setState react wont trigger the necessary routines to update the Component "view" value on screen (mentioning the first example)

  • 1
    And if you call `setState`, but are mutating the old state object, it's bound to fail eventually as it's undefined behaviour in React and discouraged. – Emile Bergeron Nov 26 '19 at 00:41
  • 1
    Reminder, the only time that it's ok to set the state manually is at the constructor of the component – Gabriel Oliveira Nov 27 '19 at 22:43