Loading…
Loading…
Learn how to use React's useOptimistic hook with Server Actions to show instant UI feedback while mutations complete in the background.
Tags
The useOptimistic hook shows instant UI changes while a Server Action runs in the background, automatically reverting if the action fails.
When a user submits a form or toggles a like button, the UI traditionally waits for the server to respond before updating. This delay makes the app feel sluggish, especially on slow connections. You could manually manage pending states, but that means tracking optimistic values, error rollbacks, and race conditions yourself.
Use useOptimistic to immediately show the expected result:
"use client";
import { useOptimistic } from "react";
import { toggleLike } from "@/app/actions";
type Message = {
id: string;
text: string;
likes: number;
likedByUser: boolean;
};
export function MessageCard({ message }: { message: Message }) {
const [optimisticMessage, setOptimisticMessage] = useOptimistic(
message,
(current, newLikedState: boolean) => ({
...current,
likedByUser: newLikedState,
likes: newLikedState ? current.likes + 1 : current.likes - 1,
})
);
async function handleToggleLike() {
const newState = !optimisticMessage.likedByUser;
setOptimisticMessage(newState); // instant UI update
await toggleLike(message.id); // server action runs in background
}
return (
<div>
<p>{optimisticMessage.text}</p>
<button onClick={handleToggleLike}>
{optimisticMessage.likedByUser ? "Unlike" : "Like"} ({optimisticMessage.likes})
</button>
</div>
);
}The like count updates immediately on click. If the Server Action fails, React automatically reverts to the real server state on the next render.
useOptimistic takes two arguments: the actual state from the server and a reducer function that computes the optimistic version. When you call the setter, React immediately renders with the optimistic value. Under the hood, React tracks that a transition is pending. Once the Server Action completes (or the parent re-renders with fresh server data), React replaces the optimistic state with the real state. If the action throws, the optimistic value is discarded and the UI snaps back to reality -- no manual rollback logic required.
Collaboration
I help startups and established companies design, build, and scale world-class digital products. From deep technical architecture to pixel-perfect UI: let's bring your vision to life.
Five essential built-in generic utility types in TypeScript that will save you hundreds of lines of code.
Generate dynamic Open Graph images in Next.js using the ImageResponse API with custom fonts, gradients, and data-driven content for social sharing.
Create reusable GitHub Actions workflows with inputs, secrets, and outputs to eliminate YAML duplication across repositories and teams efficiently.