Skip to main content

How to update state based on the previous value?

1. The problem with a regular update

Imagine a component:

javascript
function Counter() { const [count, setCount] = useState(0); const incrementTwice = () => { setCount(count + 1); setCount(count + 1); }; return <button onClick={incrementTwice}>{count}</button>; }

You expect that on click count will increase by 2... but in fact, only by 1!


Why this happens

setCount does not update count immediately (it is asynchronous). Both lines use the old value of count (for example, 0). React simply queues two identical updates:

"make count = 1".

The result is one update, value 1.


2. The correct way: functional update

React lets you pass a function to setState that receives the previous value of the state:

javascript
setCount(prevCount => prevCount + 1);

Now React guarantees that you are working with the up-to-date state, even if there were several updates in a row.


Example with incrementTwice

javascript
function Counter() { const [count, setCount] = useState(0); const incrementTwice = () => { setCount(prev => prev + 1); setCount(prev => prev + 1); }; return <button onClick={incrementTwice}>{count}</button>; }

Now on click count increases by 2, because each function receives the latest updated value.


3. Works the same way with objects and arrays

For example:

javascript
const [user, setUser] = useState({ name: "Tim", points: 0 }); function addPoint() { setUser(prev => ({ ...prev, points: prev.points + 1 })); }

Here prev is the previous user state, and you create a new object based on it.


4. Example with logging (for clarity)

javascript
function Counter() { const [count, setCount] = useState(0); const handleClick = () => { setCount(prev => { console.log("Previous value:", prev); return prev + 1; }); }; return <button onClick={handleClick}>{count}</button>; }

On every click you will see the actual "previous" value in the console, which React guarantees even with asynchronous updates.


5. Summary

What you want to doHow to write it
Set a fixed valuesetCount(10)
Increment by 1setCount(prev => prev + 1)
Add an item to an arraysetItems(prev => [...prev, newItem])
Change a field of an objectsetUser(prev => ({ ...prev, name: "Alex" }))

Conclusion

setState(value) simply sets a new state setState(prev => newValue) updates based on the previous value This is a safe way to handle:

  • several calls in a row,
  • asynchronous updates,
  • dependent computations (for example, counters, arrays, objects)

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.