patternjavascriptreactTip
useOptimistic for instant UI feedback before server confirmation
Viewed 0 times
React 19
useOptimisticoptimistic updatereact 19server actionsinstant feedbackrollback
Problem
Waiting for a server response before updating the UI makes interactions feel slow. A like button, cart add, or message send should feel instant. Rolling back on failure requires manual bookkeeping of previous state.
Solution
Use useOptimistic to apply temporary UI state while awaiting confirmation:
import { useOptimistic, useTransition } from 'react';
function LikeButton({ postId, initialLikeCount }) {
const [likeCount, addOptimisticLike] = useOptimistic(
initialLikeCount,
(currentCount, amount) => currentCount + amount
);
const [isPending, startTransition] = useTransition();
async function handleLike() {
startTransition(async () => {
addOptimisticLike(1); // instantly shows +1
await likePost(postId); // real request
// on success: optimistic state is replaced by server revalidation
// on error: optimistic state is automatically reverted
});
}
return (
<button onClick={handleLike} disabled={isPending}>
{likeCount} Likes
</button>
);
}
// With a list (add item optimistically)
function MessageList({ messages }) {
const [optimisticMessages, addOptimisticMessage] = useOptimistic(
messages,
(state, newMessage) => [...state, { ...newMessage, pending: true }]
);
// ...
}
import { useOptimistic, useTransition } from 'react';
function LikeButton({ postId, initialLikeCount }) {
const [likeCount, addOptimisticLike] = useOptimistic(
initialLikeCount,
(currentCount, amount) => currentCount + amount
);
const [isPending, startTransition] = useTransition();
async function handleLike() {
startTransition(async () => {
addOptimisticLike(1); // instantly shows +1
await likePost(postId); // real request
// on success: optimistic state is replaced by server revalidation
// on error: optimistic state is automatically reverted
});
}
return (
<button onClick={handleLike} disabled={isPending}>
{likeCount} Likes
</button>
);
}
// With a list (add item optimistically)
function MessageList({ messages }) {
const [optimisticMessages, addOptimisticMessage] = useOptimistic(
messages,
(state, newMessage) => [...state, { ...newMessage, pending: true }]
);
// ...
}
Why
useOptimistic provides a separate layer of state that is applied immediately while the async operation runs. When the async operation completes, React drops the optimistic state and uses the real updated state. If the operation throws, the optimistic state is discarded and the original state is restored automatically.
Gotchas
- useOptimistic only works inside a startTransition — wrap your async action in one
- The optimistic state is reverted automatically on error — you still need to handle error UI if needed
- Available in React 19; do not confuse with third-party optimistic update libraries
- The update function receives the current state and the optimistic value — it must return the new state
Code Snippets
Optimistic cart item add
const [optimisticCart, addOptimistic] = useOptimistic(
cart,
(state, item) => [...state, { ...item, pending: true }]
);
startTransition(async () => {
addOptimistic(newItem);
await addToCartAPI(newItem);
});Context
When building interactive features (likes, cart, comments) that need immediate UI feedback before server response
Revisions (0)
No revisions yet.