Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

JavaScript

Tyler McDonald
seal-mask
.a{fill-rule:evenodd;}techdegree seal-36
Tyler McDonald
Full Stack JavaScript Techdegree Graduate 16,700 Points

Is it necessary to use prevScore in the setScore functions?

Won't it work the same way if we just update the state like this

  const incrementScore = () => setScore(score + 1);
  const decrementScore = () => setScore(score - 1);

instead of this?

  const incrementScore = () => setScore((prevScore) => prevScore + 1);
  const decrementScore = () => setScore((prevScore) => prevScore - 1);

What are the concerns or drawbacks to updating state the first way?

1 Answer

Laura Coronel
seal-mask
STAFF
.a{fill-rule:evenodd;}techdegree
Laura Coronel
Treehouse Teacher

Hey Tyler McDonald, Great question! Guil actually went over this in his React Basics course Update State Based on Previous State.

React may batch multiple state updates into a single update for performance because of this, state maybe updated asynchronously. For our small app it wouldn't be a problem if you use:

  const incrementScore = () => setScore(score + 1);
  const decrementScore = () => setScore(score - 1);

When apps get bigger there maybe a time where you would need to call the incrementScore function twice (say you add a feature that when the player has the highest score they get an extra point). To kind of mimic this add a second setScore function in the incrementScore function and a second setScore function in the decrementScore function. BUT have one use prevScore and the other just score. Like this:

  const incrementScore = () => {
    setScore(prevScore => prevScore + 1);
    setScore(prevScore => prevScore + 1);
  }

  const decrementScore = () => {
    setScore(score - 1);
    setScore(score - 1);
  }

You will notice when you click the + button the score increments by two as we expect it. But when we click the - button the score decrements by 1. That is not what we expect and that's because in the decrementScore function both score variables equals the same number.

I hope this helps and I didn't confuse you more. Since I see you are in a Techdegree. Feel free to reach out to me on Slack if you want to go over this some more!

Tyler McDonald
seal-mask
.a{fill-rule:evenodd;}techdegree seal-36
Tyler McDonald
Full Stack JavaScript Techdegree Graduate 16,700 Points

Thanks so much for the detailed reply! That helps me understand a lot better. Definitely going to remember that tip in the future.

Follow up question. So is state always updated asynchronously, or does it depend on the situation?

Laura Coronel
seal-mask
.a{fill-rule:evenodd;}techdegree
Laura Coronel
Treehouse Teacher

🤔 Good question!

So what causes the asynchronous behavior is React's Batching.

Batching is when React groups multiple state updates into a single re-render for better performance

Before React 18, batching will only happen when you update state inside a React event handler. So in our case the setScore will be batched since the incrementScore and decrementScore are called inside React onClick event handler.

    <div className="counter">
      <button className="counter-action decrement" onClick={() => decrementScore()}> - </button>
      <span className="counter-score">{score}</span>
      <button className="counter-action increment" onClick={() => incrementScore()}> + </button>
    </div>

Here's a list of React's event handlers.

So it looks like in React 18 they introduce Automatic Batching. So now updating state will be asynchronous when you update state inside promises, setTimeout, and all event handlers.