useOptimistic

React chapter 20 · React 19 · optimistic UI · source: react.dev/reference/react/useOptimistic

The problem

The list waits for the server, so your comment seems to vanish for over a second. If you add it to local state early instead, a failed request leaves a stuck row that you must remove by hand.

The pattern that fixes it

useOptimistic(saved, reducer) shows a temporary row while the request is in flight. When the request ends, React throws the temporary version away and shows the real list, so a failure rolls back by itself.

In plain words

When you press a button, the screen can show the result right away and let the server catch up. If the server says no, the screen quietly goes back to the truth.

Writing "paid" on a receipt before the card machine finishes. If the card is declined, you cross it out. useOptimistic crosses it out for you.

Terms

optimistic UI
Show the expected result first, and confirm it with the server afterwards.
rollback
Undo the early change because the server refused it.
action
An async function run inside startTransition (or a form action). React tracks it until it finishes.

Going deeper

How does it work?

The optimistic value is computed as "confirmed state, plus a reducer applied for each action still running". You call the setter inside an async transition. As soon as that action finishes, success or failure, React stops applying it. If you also updated the real state with the saved result, the screen shows that; if not, it shows the old list again.

Pitfalls and when it does nothing

Calling the setter outside a transition or action does nothing useful and React warns. On failure the row disappears silently unless you also show an error, so always say what happened. Give each row a stable key (not the server id that only exists after saving), or the row remounts when it is confirmed.

When not to use it

Avoid it when the result is hard to predict (payments, anything the server decides), or when a wrong guess would mislead the user. A small "sending" state is better than a lie. Data libraries such as TanStack Query have their own optimistic updates, and form action plus useActionState (next chapter) pair naturally with this hook. The React Compiler does not replace it.

Keep learning

More courses

  • Jobs, linked to lessons — Browse jobs where every requirement links to the chapter that teaches it. See how ready you are, how long the gap takes to close, and which listings look stale.
  • Match a job post to courses — Paste a job post. Each skill is matched to a track here and put in learning order, foundations first.
  • Database in depth — How a query becomes work. Indexes, isolation, locks, and the plans that explain why a page is slow — not an ORM tour.
  • System Design — Eight interview case studies, from a flash sale and Tatkal to a live final and a chat model, plus JWT in separate chapters.
  • Microservices — Microservice patterns one diagram at a time: how to split a monolith, how services talk, and how data stays consistent without distributed transactions.
  • Kafka — A beginner-to-senior path through event logs, reliable delivery, production operations, and disaster recovery.
  • Frontend system design — How a UI is sliced when it is a product, not a page: ownership of state, cache, routes, and what happens when the network lies.
  • CSS in depth — See the box, then the page. Visual chapters from the box model through Flexbox surprises, Grid, selectors, and units, then backgrounds, shapes, and visual effects, each with a playground.
  • Accessibility — HTML labs first, then a full pass of WAI-ARIA 1.3: naming, every state, widget and structure roles, live regions, ariaNotify, and relationships.
  • Docker — What an image is, why layers cache, and how containers find each other on a network.
  • Redis — Fifteen Redis patterns, one picture each: cache, session, lock, counter, rate limiter, queue, and when Redis is the wrong tool.