FAQ: The State Hook - Set From Previous State

I have the same question.

1 Like

prevQuestionIndex and the fact that it doesn’t seem to be defined is not covered in the above video, so don’t watch it if that’s what you want to know! Instead look at the functional updates section in the react docs which explains that if you pass a function to setState the function will receive the previous value. So ‘prevQuestionIndex’ is just the variable name this tutorial gives to the previous state value but it could be anything.

9 Likes

Great to have these discussion pages. Its clear that this lesson is a pretty large step up, compared to the others, and I agree some features are added and not explained too well, so you have to dig around to find how things work.
My question is about how onLastQuestion and onFirstQuestion are being updated. Since they are not state or props, how are they being excecuted? As the questionIndex changes, the true or false values of onLastQuestion and onFirstQuestion are updated. My guess is that because their value depends on a state value, they are being updated automagically when the state value changes ? Can anyone confirm or deny this ?

1 Like

it happens all the time to me, everything can be working the way it is suppose to and still not pass me even if its the same exact code. this website is buggy and it sucks because I’ve tried other sites and this is the best one for me but its so frustrating

I just wanna know how can someone get to the solution by just reading this step:

Add an onFirstQuestion variable with a boolean value then use that value to toggle the disabled attribute of the “Go Back” button on and off.

This lesson is poorly designed and there aren’t any hints to suggest anything.
I just don’t understand how one can get to this code…

const onFirstQuestion = questionIndex === 0;
............
<button disabled={onFirstQuestion} onClick={goBack}>

…by just reading that step!

I have 2 questions for exercise 5:

  1. In the instruction, why use a callback function inside of setCount? Is it so the there is better error handling?
  const increment = () => setCount(prevCount => prevCount + 1);
  1. In the coding exercise part, what is determining the last question is 5? I only see:
  const onLastQuestion = questionIndex === questions.length - 1;

1 Like

Hey does anyone know how i could display both the items and their indexes !?

import React, {useState} from ‘react’;
import ReactDOM from ‘react-dom’;

let questions = [‘why’,‘what’,‘where’,‘when’];

function QuestionScroll () {

  • const [counter,setCounter] = useState(0);*

  • const increment = () =>{*

  • setCounter((prev) => prev +1 );*

  • }*

  • const decrement = () =>{*

  • setCounter((prev) => prev -1 );*

  • }*

  • const firstQ = counter === 0;*

  • const lastQ = counter === questions.length -1;*

  • return (*

  • *
  •  <h2>QUESTION : #{counter}</h2>*
    
  •  <button onClick={decrement} disabled={firstQ}>Go back</button>*
    
  •  <button onClick={increment} disabled={lastQ}>Go forward</button>*
    
  • *
  • )*
    }

ReactDOM.render(,document.getElementById(‘app’));

How can i render both the items and their indexes as the i iterate through the array!?

import React, {useState} from ‘react’;
import ReactDOM from ‘react-dom’;

let questions = [‘why’,‘what’,‘where’,‘when’];

function QuestionScroll () {
const [item,setItem] = useState(“why”);
const [counter,setCounter] = useState(0);

const increment = () =>{
let newName =questions.map((item,index)=>{
setCounter((index)=> index + 1);
setItem(item);
});
}

const decrement = () =>{
let newName =questions.map((item,index)=>{
  setCounter((index) => index - 1);
  setItem(item);
});

}

const firstQ = counter === 0;
const lastQ = counter === questions.length -1;

return (


QUESTION : #{counter} : {item}


Go back
Go forward

)
}

ReactDOM.render(,document.getElementById(‘app’));

I was having the same problem until i saw this lol

If like me you found this lesson a little hard to understand, taking a look at the React docs was quite helpful. I didn’t understand initially why passing a callback function to the useState hook would return an updated value using the previous state. This is however a feature of the React library, something this lesson didn’t make obvious.

The example used in the docs is the following:

function Counter({initialCount}) {
  const [count, setCount] = useState(initialCount);
  return (
    <>
      Count: {count}
      <button onClick={() => setCount(initialCount)}>Reset</button>
      <button onClick={() => setCount(prevCount => prevCount - 1)}>-</button>
      <button onClick={() => setCount(prevCount => prevCount + 1)}>+</button>
    </>
  );
}

I refactored this code to make it slightly easier to read for new JavaScript learners:

function Counter(props) {
  const [count, setCount] = useState(props.initialCount);
  return (
    <>
      Count: {count}
      <button onClick={() => setCount(props.initialCount)}>Reset</button>
      <button onClick={() => setCount((prevCount) => prevCount - 1)}>-</button>
      <button onClick={() => setCount((prevCount) => prevCount + 1)}>+</button>
    </>
  );
}

When either the “+” or “-” button is clicked, the callback function is invoked with one argument, the value stored in the previous state.

1 Like

Hello,

What is react doing internally here?

setCount(prevCount => prevCount + 1);

Regards,

Luis

2 Likes

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