FAQ: The State Hook - Set From Previous State

Hello,

Could you explain this?

setCount(prevCount => prevCount + 1);

Regards,

Luis

same question here.

setCount(prevCount => prevCount + 1);

Hi, povedaaqui.
I had all the same questions as you and other people, it turns out that “useState()” returns an array like this: [undefined, function()]. Whatever you put inside of the parenthesis of useState() it’s what you get in return as the first item of the array.
Now, to explain the code that you are asking for.
setCount() is set as the function that useState() returns using array destructuring, the prevCount is the parameter that is passed to the function each time we call it, in this case, is 0. So, the function is setting the previous state of 0 to 1, or in any case, is summing one to the previous count.
Hope it helps.

I found this exercise poorly designed, I follow the steps and see the tips and nothing passes, I check with the view solution and it’s exactly the same and still doesn’t pass.

Also, I found it very confusing.

Why must we use arrow functions. UGHH

1 Like

I have a similar question, very confused as to how setCount(prevCount => prevCount + 1); works.

How does prevCount get populated with the right value out of the state object? We don’t do any de-structuring of the state to achieve this? It just seems to happen magically and is not explained

Hi,

For this lesson, we’re instructed the callback functions should look like this:

const increment = () => setCount(prevCount => prevCount + 1);

Doesn’t prevCount need to be passed to the function? Like so:

const increment = (prevCount) => setCount(prevCount => prevCount + 1);

I’m seeing similar questions here but not a clear answer. Could someone please confirm? Thanks!

1 Like

By using the useState hook, a lot of things pertaining to state are handled for us.
For example,

const [count, setCount] = useState(0);

This is initializing the state of count to 0 and also giving us a means of changing state via the setCount state setter. The initial value of the state can be chosen to be a number, string, boolean, array, object, whichever is appropriate.
Under the hood away from our sight, the state setter setCount has been implemented in such a way that it can be used in two ways. We could a) pass a value to the state setter or b) pass a function to the state setter. The state setter is able to recognize whether it has been passed a value or a function.
a) If simply a value is passed to the state setter, then it replaces the old state with the new state.

const [count, setCount] = useState(0);
// ...
setCount(13); 
// This will overwrite the state of count.
// 0 will be replaced by 13.

b) The second way to use a state setter is by passing it a function. The state setter is able to distinguish between a value and a function. This function is expected to return some value, which will then be used by the state setter to set the new state. To make things easy for us, if the function has a parameter, then the state setter will automatically pass the previous state as an argument. We don’t have to worry about explicitly providing the previous state to the state setter. It will be taken care for us. We can name our parameter whatever we want. The state setter will recognize that it has been passed a function with a parameter, so it will automatically assign the previous state to this parameter. When we want to preserve the existing old value or want to use the old value in some calculation to arrive at a new value, then this approach allows us that flexibility.

// Suppose the current count is 13

setCount(prevCount => prevCount + 1);
// setCount will recognize that this is a function. 
// It will automatically pass 13 as the argument and assign it to prevCount.
// The arrow function increments the previous count by 1.
// An implicit return of 14 is made. setCount then sets count to be 14.
// If we had more than one statement in the body of the arrow function,
// we could use curly braces and then do an explicit return of the new value.

In our case, we have picked prevCount as the parameter name. There is nothing special about the name prevCount. We could have picked a different name, but prevCount is a good choice as it reminds us of the word previous. We could have picked abc as the parameter name, but that would be a poor choice in terms of readability. We should pick names that help the reader understand the code, rather than picking random names.
In the documentation, see
https://reactjs.org/docs/hooks-reference.html#functional-updates

const increment = () => setCount(prevCount => prevCount + 1);

is correct. setCount is responsible for providing and assigning the previous state to prevCount. Not our responsibility.

8 Likes

This is really helpful, thank you! I couldn’t find any explanation for this syntax on Codecademy docs, so maybe it could be added into the lesson somewhere? It had me very confused!

1 Like

It’s just quite the omittance to not let anyone know that the hooks are so created that the arrow function inside setState just does, by nature, get the previous state for an argument. If that is not mentioned then one is left to guess as to what happens. And guess you might but we are here to understand, not to guess.
From the react docs:
If the new state is computed using the previous state, you can pass a function to setState . The function will receive the previous value, and return an updated value. Here’s an example of a counter component that uses both forms of setState :

2 Likes

Amazing explanation - thank you!

1 Like

This kind of function in React is called Updater function.
Check it out in the React documentation:
Updating state based on the previous state

In a nutshell, the value passed to the callback function is automatically populated by React with the current state value. You can call this value whatever you want (`prevCount in the Codecademy example)

1 Like

I have found this helpful:

1 Like

Dude you’re a life save. Thanks. Was beating my head against the desk trying to figure out WTH prevQuestionIndex was and why it’s never defined.

1 Like

Hello, could anyone clarify what’s happening in line 7 and 8 with the callback functions? Particularly: can anyone explain where prevQuestionIndex (which is a variable, correct?) is getting its value (which is questionIndex correct?)?

import React, { useState } from 'react';

export default function QuizNavBar({ questions }) {
  const [questionIndex, setQuestionIndex] = useState(0);

  // define event handlers 
    const goBack = () => setQuestionIndex(prevQuestionIndex => prevQuestionIndex - 1);
    const goToNext = () => setQuestionIndex(prevQuestionIndex => prevQuestionIndex + 1);
  // determine if on the first question or not 

  const onLastQuestion = questionIndex === questions.length - 1;

  return (
    <nav>
      <span>Question #{questionIndex + 1}</span>
      <div>
        <button onClick={goBack}>
          Go Back
        </button>
        <button disabled={onLastQuestion}>
          Next Question
        </button>
      </div>
    </nav>
  );
}

Have a look at this post: FAQ: The State Hook - Set From Previous State - #43 by mtrtmk

If something is still unclear, share your thoughts on what you find confusing.

1 Like

This was clear to the depth that I need to work with the language. Thank you for such a lucid breakdown. CC should have you write “in-depth” articles to accompany these more complicated lessons!

Thank you! The React link was extremely helpful!

Maybe this is a personal preference or a misunderstanding, but it seems to me that the event handlers could have been written if we had named the argument currentQuestionIndex instead of prevQuestionIndex. Doesn’t that make logical sense? goBack = current - 1. goToNext = current + 1.

Am I misunderstanding something? Prev - 1 = back 2 in my head…

I think I figured out my misunderstanding here. It is convention to refer to the previous state with the prefix ‘prev’. My confusion was due to how this seems to refer to the previous index, but it’s referring to the previous state that we are updating with the setter function.

1 Like