Headline: React 19's
useOptimisticshows the result of an action before the server confirms it. The API is tiny; the mental model is where people trip. Here's what held up across a comment box, a like button, and a settings form â plus three edges that cost me an afternoon each.
The mental model
useOptimistic stores nothing durable. It's a view over your real state that is only live while a transition is pending.
const [optimistic, addOptimistic] = useOptimistic(
realState,
(current, action) => nextState
);
The first arg is the source of truth; the second is a pure reducer. The instant your action resolves and realState updates, React throws the optimistic value away and re-renders from truth. You never manually roll back.
Pattern 1: append on submit
const [optimisticComments, addOptimistic] = useOptimistic(
comments,
(state, text: string) => [...state, { id: crypto.randomUUID(), text, pending: true }]
);
The pending flag drives a dimmed style; the server action revalidates the list so it refreshes from source.
Pitfall 1: fire it inside a transition
Calling addOptimistic from a plain onClick makes the value flash and vanish â there's no pending transition to keep it alive. Always trigger it from a form action or startTransition.
Pattern 2: toggle with a count
const [state, toggle] = useOptimistic(
{ liked, count },
(s) => ({ liked: !s.liked, count: s.count + (s.liked ? -1 : 1) })
);
Because the reducer receives the current optimistic value, rapid double-clicks compose correctly instead of fighting a stale closure.
Pitfall 2: errors need their own signal
useOptimistic has no error channel. When the action throws, the optimistic value disappears â correct â but the user gets no explanation. Pair it with useActionState or a toast.
Pitfall 3: unique temporary keys
Reusing id: 'temp' for every pending row makes React merge concurrent entries. Give each optimistic item a unique temp key and let the server row replace it on revalidation.
When I skip it
For low-confidence writes â payments, destructive deletes, heavy validation â I keep an honest pending state. Showing success you can't guarantee erodes trust faster than a spinner.
Originally published on devya.dev. Also on eng-ahmed.com. Built by Devya Solutions.
Top comments (0)