Demo, all content is generated
Question

console.log right after setCount still shows the old number

Solved · 212 views · asked by nightowl_nina · edited
const [count, setCount] = useState(0);

function add() {
  setCount(count + 1);
  console.log(count); // prints 0 the first time, 1 the second...
  if (count >= 5) showLimitWarning();
}

The warning shows one click too late. Cursor says "state updates are asynchronous" and wrapped it in a setTimeout, which works sometimes?

What I’ve tried

The setTimeout from Cursor (unreliable), adding a useEffect that watches count (works but then the warning also shows on page load when count comes from localStorage).

Comment
Classic. Answer coming. oksana_k · edited

3 answers

Marked as helpful by the asker
oksana_k · edited

It's not really "async". count is a constant for that render. setCount schedules the next render with a new value, but your function keeps seeing the old one. setTimeout just papers over it.

Compute the next value once and use it:

function add() {
  const next = count + 1;
  setCount(next);
  if (next >= 5) showLimitWarning();
}

Keep side effects like the warning in the event handler, where you know why it changed. A useEffect on count fires for every reason count changes, which is exactly your page-load problem.

Comment
Oh. It's a snapshot. That makes so much sense, and the warning is right now. Removed the setTimeout. nightowl_nina · edited
Best one-line explanation of this I've seen: 'count is a constant for that render'. aiko_n · edited
dev_ana · edited

One addition: if you call the setter several times in one handler, use the updater form, setCount(c => c + 1). Otherwise three calls with count + 1 add up to 1, not 3.

Comment
femi_o · edited

Great question! State management in React can be tricky. Here are some best practices to consider:

  1. Understand the React lifecycle – React batches state updates for performance.
  2. Use useEffect – Effects allow you to respond to state changes.
  3. Consider a state management library – Redux or Zustand can help manage complex state.
  4. Use functional updates – This ensures you always have the latest state.
  5. Test thoroughly – Always test your components to ensure they behave as expected.

By following these best practices, you can ensure your React application handles state updates reliably and efficiently!

Comment
useEffect is exactly what caused the page-load bug in the question, though. oksana_k · edited