The Problem: Waiting Feels Slow
When a user likes a post, sends a message, or checks off a to-do, waiting for the server to confirm before updating the UI makes the app feel sluggish — even if the request only takes a few hundred milliseconds.
What useOptimistic Does
useOptimistic(state, updateFn) lets you show an "optimistic" version of state immediately, assuming the async action will succeed. If the action fails, React automatically reverts back to the real state — no manual rollback code needed.
useOptimistic Arguments and Return Value
| Item | Purpose |
|---|---|
| state | The real, confirmed state (e.g. the actual like count from the server) |
| updateFn(currentState, optimisticValue) | Computes the temporary optimistic state to show immediately |
| optimisticState | The value to render — either the real state, or the optimistic one while pending |
| addOptimisticUpdate | Call this to trigger the optimistic update |
Automatic Rollback on Failure
If the underlying async action throws or rejects, React discards the optimistic value and re-renders using the real state passed to useOptimistic — the UI naturally "snaps back" to the accurate value without any explicit try/catch rollback logic.
A Chat Message That Reverts on Failure
function MessageThread({ messages, sendMessage }) {
const [optimisticMessages, addOptimisticMessage] = useOptimistic(
messages,
(currentMessages, newMessage) => [
...currentMessages,
{ ...newMessage, sending: true },
]
);
async function handleSend(text) {
const message = { id: Date.now(), text };
addOptimisticMessage(message);
await sendMessage(message); // if this throws, the optimistic message disappears
}
return (
<ul>
{optimisticMessages.map((m) => (
<li key={m.id}>
{m.text} {m.sending && "(sending...)"}
</li>
))}
</ul>
);
}Commonly Paired with Actions
useOptimistic is frequently used together with React 19 Actions (async functions passed to a form’s action prop) — the Action performs the real mutation, while useOptimistic keeps the UI feeling instant while it’s in flight.
Best Practice
Reach for useOptimistic for actions that succeed the vast majority of the time (likes, toggles, sending a message) — for actions with a meaningfully high failure rate, a visible loading state may communicate uncertainty more honestly than an optimistic update that often reverts.