useOptimistic
Show instant UI updates before the server confirms — then reconcile automatically
Waiting for a server before updating the UI feels sluggish. useOptimistic lets you show the expected result immediately, then automatically fall back to the real state when the async work finishes. This is how fast apps feel fast.
The Problem: Perceived Latency
Send a chat message and wait 800ms for the server before it appears? That feels broken. Users expect the message to show instantly and quietly confirm in the background. That's an optimistic update: assume success, show it now, reconcile later.
The Hook
useOptimistic layers a temporary optimistic value on top of your real state:
const [optimisticState, addOptimistic] = useOptimistic(
realState,
(currentState, optimisticValue) => {
// return the new state to show *while* the async action runs
return [...currentState, optimisticValue]
}
)
realState— your actual, confirmed state- the reducer — computes what to display optimistically
addOptimistic(value)— call it to apply an optimistic update
The key behavior: while an action (a transition) is in flight, optimisticState reflects your optimistic guess. When the action completes and realState updates, React automatically discards the optimistic layer and shows the real value. If the action fails and you don't update real state, it reverts — no manual rollback.
A Chat Example
function Chat({ messages, sendMessage }: Props) {
const [optimistic, addOptimistic] = useOptimistic(
messages,
(msgs, text: string) => [...msgs, { text, sending: true }]
)
async function action(formData: FormData) {
const text = String(formData.get("text"))
addOptimistic(text) // show it immediately
await sendMessage(text) // real network call
// real state now includes the message; optimistic layer drops away
}
return (
<>
{optimistic.map((m, i) => (
<p key={i} style={{ opacity: m.sending ? 0.5 : 1 }}>
{m.text}
</p>
))}
<form action={action}>
<input name="text" />
</form>
</>
)
}
Try It Live
Send a message and watch it appear instantly as “sending…”, then flip to “sent ✓” after the simulated server delay:
Notice the message appears instantly as “sending…”, then confirms after the simulated 1.2s server delay.
The optimistic value only holds while an async action/transition is pending
— which is exactly what a form action (or startTransition) provides.
React reconciles back to real state as soon as that work settles.