useOptimistic: UI that doesn't wait for the server
A like that lights up instantly and a chat message that appears before the server stores it. And if something fails, React rolls it back for you.
Optimistic UI is the trick that makes apps feel instant: you show the result of an action right away and let the server confirm it in the background. React 19 gives us a hook for it: useOptimistic.
Signature
const [optimisticState, addOptimistic] = useOptimistic(state, updateFn);state— the "true" value (from props or from the server),updateFn(current, optimisticValue)— a pure function returning the optimistic version,addOptimistic(value)— called inside an action orstartTransition.
While the action is running, optimisticState is rendered. When it finishes, React goes back to the current state — whether the action succeeded (and state now contains the new item) or failed (and the optimistic change simply disappears).
Example: a chat
"use client";
import { useOptimistic } from "react";
type Message = { id: string; text: string; sending?: boolean };
export function Thread({ messages, send }: {
messages: Message[];
send: (text: string) => Promise<void>;
}) {
const [optimistic, addMessage] = useOptimistic(
messages,
(current, text: string) => [
...current,
{ id: crypto.randomUUID(), text, sending: true },
],
);
async function action(formData: FormData) {
const text = String(formData.get("text"));
addMessage(text);
await send(text); // server action, then data revalidation
}
return (
<>
<ul>
{optimistic.map((m) => (
<li key={m.id} style={{ opacity: m.sending ? 0.5 : 1 }}>{m.text}</li>
))}
</ul>
<form action={action}>
<input name="text" />
</form>
</>
);
}Gotchas
- Calling
addOptimisticoutside an action or transition logs a warning and the change is discarded immediately. - Optimistic state is temporary. The source of truth must arrive through
stateafter the action — usually via data revalidation or asetStateinside the transition. - Show the user that the item is still saving (opacity, a clock icon). Optimism doesn't mean lying.