Props and state

State is a snapshot

Understand why a state variable does not change inside the event handler that has already captured the current render.

Every render receives a snapshot of props and state. The event handlers created during that render keep seeing that snapshot.

Consider three updates in one click:

function Counter() {
  const [count, setCount] = useState(0)

  function addThree() {
    setCount(count + 1)
    setCount(count + 1)
    setCount(count + 1)
  }

  return <button onClick={addThree}>{count}</button>
}

If count is 0, every line requests setCount(0 + 1). The next render shows 1, not 3.

When the next value depends on a queued previous value, pass an updater function:

setCount(current => current + 1)
setCount(current => current + 1)
setCount(current => current + 1)

React processes the queue in order: 0 → 1 → 2 → 3.

Snapshots also explain delayed handlers:

function showLater() {
  setTimeout(() => alert(count), 2000)
}

The alert sees the count from the render that created showLater, even if another render happens before the timer runs.

This behavior prevents a running handler from changing underneath you. Use an updater when calculating the next state from previous state. Use a ref only when an asynchronous callback genuinely needs the latest mutable value without rendering it.

Try both addThree versions and predict the result before clicking.

Lesson completed

Take this course offline

Get every free book, course edition, and software download.

Get the download library →