• Home
  • Skills
  • Projects
  • Blog
  • Contact
Resume
Naser Rasouli

Author

Naser Rasouli

Front-End developer - sharing lessons learned, notes, and write-ups from real projects.

GitHubLinkedIn

Last posts

BEM Methodology in CSS: predictable naming for clean styles
2026-02-18•1 min read

BEM Methodology in CSS: predictable naming for clean styles

A practical guide to BEM to avoid style conflicts, structure class names, and keep CSS maintainable.

Cleanup Functions in useEffect: Stop Leaks Before They Start
2026-02-04•1 min read

Cleanup Functions in useEffect: Stop Leaks Before They Start

A practical guide to writing cleanup in useEffect so you avoid memory leaks, duplicate listeners, and setState on unmounted components.

Frontend Interview Flow: Stages, Signals, and Prep
2026-01-17•1 min read

Frontend Interview Flow: Stages, Signals, and Prep

A frontend interview isn’t just a few HTML/JS questions—it’s a path to gauge web understanding, problem solving, and collaboration. This guide outlines common stages, what interviewers look for, and how to prepare.

Why console.log After setState Shows the Old Value

Why console.log After setState Shows the Old Value

2026-02-04
reactstatesetStatehooksuseEffect

Introduction

If you call setState (or setCount) and immediately console.log, you’ll often see the old value. That’s not a bug. React deliberately makes state updates asynchronous and batched to avoid extra renders. This guide explains why that happens and how to read the updated state correctly.


Why doesn’t state change immediately?

  • setState doesn’t change the value on the spot; it enqueues an update request.
  • JavaScript keeps running, and React applies the new state on the next render.
  • Any code running right after setState still sees the previous value.

Behind the scenes:

  1. setCount is called.
  2. React puts the update in a queue.
  3. The rest of your JS keeps executing.
  4. React re-renders and the new state becomes available.

Basic example

const [count, setCount] = useState(0);

const handleClick = () => {
  setCount(count + 1);
  console.log(count); // still the previous value
};

console.log runs before the next render, so it logs the old state.


How to read the fresh value

Use useEffect

useEffect(() => {
  console.log(count); // always the updated value
}, [count]);

useEffect runs after render, so the logged value is current.

Use a Functional Update

When the new value depends on the previous one, the functional form always has the latest state:

setCount(prev => {
  const next = prev + 1;
  console.log(next); // the new value is here
  return next;
});

Back-to-back updates

Common mistake:

setCount(count + 1);
setCount(count + 1); // both use the stale value

Result is only +1. Correct version:

setCount(prev => prev + 1);
setCount(prev => prev + 1); // total +2

Functional updates ensure each call uses the latest state.


Where you need to be careful

  • Logging immediately after setState
  • Sending state to an API right after updating
  • Branching logic that uses the state in the same tick
  • Multiple sequential updates on one state without the functional form

Use useEffect or functional updates in these cases.


Quick checklist

  • Does the update depend on the previous value? → Use the functional form.
  • Need the fresh value? → Log inside a useEffect that depends on that state.
  • Doing multiple updates in a row? → Make them all functional so batching works.

Wrap-up

Seeing the old value after setState is expected: React queues and batches updates. To get the new state, either wait for the next render (useEffect) or use the functional updater. Rule of thumb: “If you need the previous state, use a function; if you need the new state, read it after render.”