Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding PrevState in React

Tags:

reactjs

I am new to React and this might be a silly doubt. But I wasn't able to find the answer for this. When using state in React, to keep the display updated we use PrevState. For example:

const [state, setState] = useState(0);
setState(prevState => prevState +1);

I understand that prevState updates the state by 1 and keeps the UI up to date with the state value.

However, how is prevState assigned the value of the previous state. Isn't it just the name of the parameter of the arrow function? So how is this name assumed to be the previous state value? In forEach loop the parameter represents an element of the list. But here, how is the parameter PrevState being assigned the value?

like image 289
Leo Avatar asked Oct 28 '25 01:10

Leo


1 Answers

Internally, React keeps an array of all states for a given instance of a component. For example, if you have

const comp = () => {
  const [state, setState] = useState(0);
  const clickHandler = () => setState(prevState => prevState +1);
  return <button onClick={clickHandler}>click</button>
};

Then, because there's only one state for the component, on mount, React will have an array of one item that it stores internally:

[0]

When useState is called, the value that React currently has in its internal array for that state gets returned. So, with the above example, when you click, the state setter will tell React to update its internal state to:

[1]

After which the component re-renders due to the state change, so the state value returned by useState that re-render is 1.

When you use the callback form of the state setter, eg

setState(prevState => prevState +1);

The callback's parameter comes directly from React's internals. This can sometimes be more reliable than relying on the value in the outer state identifier, because the outer state value will be out of date if you previously set the same state without waiting for a re-render - for example, notice how the below increments the state by only 1 each click, rather than by 2.

const App = () => {
    const [count, setCount] = React.useState(0);
    const clickHandler = () => {
      setCount(count + 1);
      setCount(count + 1);
    };
    return (
      <div>
        {count}
        <button onClick={clickHandler}>click</button>
      </div>
    );
};

ReactDOM.createRoot(document.querySelector('.react')).render(<App />);
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<div class='react'></div>

In contrast, if you use the callback version, as soon as you call the first state setter, React's internals for the state will be updated - and then the second time you call the state setter, the parameter passed will be the newly updated value React has in state for it:

const App = () => {
    const [count, setCount] = React.useState(0);
    const clickHandler = () => {
      setCount(count => count + 1);
      setCount(count => count + 1);
    };
    return (
      <div>
        {count}
        <button onClick={clickHandler}>click</button>
      </div>
    );
};

ReactDOM.createRoot(document.querySelector('.react')).render(<App />);
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<div class='react'></div>

The callback approach is only needed if you have the possibility of a stale closure. If the value in state has no chance of being stale, then there's no need for the callback, and simply doing

setCount(count + 1);

will work fine.

like image 156
CertainPerformance Avatar answered Oct 30 '25 15:10

CertainPerformance



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!