DEV Community

Discussion on: When should we use the appropriate way to set state?

Collapse
 
dance2die profile image
Sung M. Kim • Edited

** update **
Woops, 😅 I didn't catch that #explainlikeim5 tag...


Hi Brian,

Those two examples are actually recommended ways.
From what I read from docs, following examples are the wrong ways.

Do Not Modify State Directly

// Wrong
this.state.comment = 'Hello';

👆 is wrong because (short answer is that) React would not know whether this.state.comment is updated without this.setState(...).

Longer answer is due to React tracks state changes (Reconciliation).

A state is an object, thus a reference type. Checking whether each state in each object for all components in React tree would be prohibitively slow. So when you are doing this.setState({comment: 'Hello'}), you are basically setting a new reference for this.state and alerting React to queue the changes for render later.

When you do this.state.comment = "Hello", you didn't change the reference of this.state but only the value pointed by the reference thus React would not know that the state has changed.

State Updates May Be Asynchronous

// Wrong
this.setState({
  counter: this.state.counter + this.props.increment,
});

For this case, while you are changing counter state within this.setState, either this.state.counter & this.props.increment could have a difference value from the time you tried to set the counter value.

Suppose that in your code

// at the time you are calling `this.setState`
// `this.state.counter` is 1
// and `this.props.increment` is 1
this.setState({
  counter: this.state.counter + this.props.increment,
});

As setState is asynchronous, when React is trying to apply the setState, values for this.state.counter or/and this.props.increment (such as 2, 3, etc) could have changed by external event/side effects (e.g. setInterval, mouse, keyboard events, etc).

When you use the "correct" callback version,

// Correct
this.setState((state, props) => ({
  counter: state.counter + props.increment
}));

React knows what the previous state & props were and gives you the snapshot of those values, thus no need to worry about it being changed elsewhere.

I could be missing something or wrong somewhere.

If so, would anyone kindly point out my mistakes? 🙂 Thanks.

Collapse
 
briang123 profile image
Brian Gaines

Hi Sung,

Thanks for your reply!

Perhaps my question wasn't clear enough, sorry for that. I posted the two options (from the React docs) knowing that those were the correct ways to implement state, BUT my question is when to use one over the other. Why are there two correct ways when Option 2, IMO, should always be used. Why have Option 1, when there's Option 2? Hope that clears it up.

Collapse
 
dance2die profile image
Sung M. Kim • Edited

Yikes.. I am sorry I misunderstood the question 😰

How I understood was that they are basically the same providing devs multiple ways to do the same thing depending on your need.

So if you don't need to use previous state or props, then go with option 1 else option 2.

Unrelated to the main question,
For memoization in React Hooks, they have two different ways to memoize (useCallback & useMemo, which do the same thing but useCallback is called like Option 1 of setState, while useMemo is called like Option 2 of setState).

Official doc shows that

useCallback(fn, inputs) is equivalent to useMemo(() => fn, inputs).

But I don't know enough history about React why there is only setState but two for memoization 😅