Setting state inside an async function without using functional updates can lead to stale state issues because the state may not reflect the latest updates when the async operation completes.
Why This Happens:
When you set state like this:
setCount(count + 1); // Potential issue
If the count
variable is from an earlier render, it might not be the latest value when the async function resolves.
Correct Approach Using Functional Updates:
Use a function to get the latest state:
setCount(prevCount => prevCount + 1);
This ensures the state update always uses the latest value, even if the async function delays the update.
Example – Incorrect vs Correct:
Incorrect (Stale State Issue):
const [count, setCount] = useState(0);
const handleClick = async () => {
await fetchData(); // Assume this takes time
setCount(count + 1); // May use stale count
};
Correct (Using Functional Update):
const [count, setCount] = useState(0);
const handleClick = async () => {
await fetchData();
setCount(prevCount => prevCount + 1); // Always updates with the latest count
};
When Does This Matter?
- Multiple rapid clicks in a button (async calls overlapping).
- Loops that update state asynchronously.
- Dependent state updates in complex UIs.