DEV Community

useOptimistic in React 19: Patterns and Pitfalls from Real Forms

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.

Comments

No comments yet. Start the discussion.