
The React docs for useActionState and useOptimistic have been rewritten with clearer naming, new interactive sandboxes, and patterns from simple pending states to shopping carts with error recovery. Here's what changed and why it matters.
Aurora Scharff
February 24, 2026
If you tried learning useActionState or useOptimistic from the original React 19 docs and came away confused, now is a great time to go back. Both pages have been completely reworked with new interactive sandboxes, clearer naming, and practical patterns. useActionState now covers queuing, cancellation, error handling, and form integration. useOptimistic walks you from simple pending indicators all the way to reducers and error recovery.
The useActionState docs now use consistent naming that makes the API easier to follow:
const [state, dispatchAction, isPending] = useActionState(reducerAction, initialState);
The function you pass in is called a reducerAction. It takes the previous state, does some work (which can be async, like calling an API), and returns the new state. The function you get back is dispatchAction, which you call to trigger that work. This naming makes the data flow clear and helps distinguish the hook from useReducer.
A common question is: what happens when you call dispatchAction multiple times quickly? The docs now include a deep dive that explains this. Actions run one after the other, not at the same time. Each action waits for the previous one to finish, because the result of one is passed as input to the next.
If that sequential behavior isn't what you want, the docs cover two alternatives: using useOptimistic to show immediate feedback while actions are still processing, or cancelling queued actions with an AbortController so new actions can skip ahead.
If your component needs to handle more than one kind of action (for example, both adding and removing items), the docs show how to dispatch different action types through the same hook. A deep dive compares useActionState and useReducer directly: use useReducer when your state logic is pure (no API calls), and useActionState when you need side effects like server requests.
The error handling section covers two strategies. For expected errors like validation failures, you return the error as part of your state and display it in the UI. For unexpected errors, you throw them and let Error Boundaries handle the fallback.
There's also a new section on using useActionState with forms. When you pass dispatchAction as a <form> action prop, React handles the transition for you automatically.
The troubleshooting section has been expanded too, with answers to common issues like isPending not updating or actions being skipped.
The useOptimistic docs have seen the biggest improvement. Where the old page had a single form example, the new version walks you through a full progression of patterns, from a basic like button to a shopping cart with error recovery. If useOptimistic felt unclear before, this is the page to revisit.
The docs now name the return values consistently:
const [optimisticState, setOptimistic] = useOptimistic(value, reducer?);
You pass in the current value (from props or state), and get back optimisticState, a temporary version that updates immediately inside a transition. The setOptimistic function is what triggers the optimistic update. You can also pass an optional reducer for more complex state calculations.
The core idea behind useOptimistic is instant feedback. Instead of waiting for the server to confirm an action, you show the expected result right away. If the server disagrees, React rolls back automatically.
The simplest form is passing a value directly to setOptimistic:
const [optimisticLiked, setOptimisticLiked] = useOptimistic(liked);
startTransition(async () => {
setOptimisticLiked(true);
await toggleLike();
});
The like state updates instantly. When the transition completes, optimisticLiked settles to whatever liked actually is.
You can also pass an updater function, just like useState:
const [optimisticCount, setOptimisticCount] = useOptimistic(count);
startTransition(async () => {
setOptimisticCount(c => c + 1);
await incrementOnServer();
});
The useOptimistic docs now include patterns that build on the action prop pattern from the useTransition docs. The idea is that a reusable component handles transitions and optimistic updates internally, while the parent passes in the async work through an action prop. The component takes care of showing pending state and immediate feedback, and the parent only needs to describe what should happen, not how to coordinate it. For a practical walkthrough of this pattern, see Building Reusable Components with React 19 Actions.
One example uses useOptimistic(false) for pending state. The component immediately shows a loading indicator when the action starts, then automatically reverts when it finishes:
function Button({ action, children }) {
const [isPending, setIsPending] = useOptimistic(false);
return (
<button
disabled={isPending}
onClick={() => startTransition(async () => {
setIsPending(true);
await action();
})}
>
{isPending ? 'Submitting...' : children}
</button>
);
}
The refreshed useActionState docs also show this pattern. A stepper component combines useOptimistic with useActionState, where the parent provides increaseAction and decreaseAction props and the stepper encapsulates optimistic updates and state management internally:
function QuantityStepper({ value, increaseAction, decreaseAction }) {
const [optimisticValue, setOptimisticValue] = useOptimistic(value);
function handleIncrease() {
startTransition(async () => {
setOptimisticValue(c => c + 1);
await increaseAction();
});
}
return <span>{optimisticValue}</span>;
}
A new deep dive explains what happens under the hood: when you set an optimistic value, React shows it right away. It stays visible while your async work runs. Once the real state update comes through, the optimistic value and the real value merge in a single render. There's no flicker or extra re-render to "reset" it.
As your needs grow, the docs show how to pass a reducer to useOptimistic to update multiple related values at once. For example, a follow button that needs to update both the button label and the follower count:
const [optimisticState, setOptimistic] = useOptimistic(
{ isFollowing, followerCount },
(current, newFollowing) => ({
isFollowing: newFollowing,
followerCount: current.followerCount + (newFollowing ? 1 : -1),
})
);
A deep dive helps you decide when a simple updater function is enough versus when you need a reducer. The docs also cover handling multiple action types through a single reducer, showing how useOptimistic scales to more complex UI where you might have add, remove, and update operations all in one place.
The final new section covers error recovery. When you optimistically update something but the server rejects it, useOptimistic rolls back to the real state automatically when the transition ends. The docs show how to combine this with error handling to give users clear feedback about what went wrong.
These two hooks are central to building responsive async UIs in React 19, and the docs now do a much better job of showing you how. Every section includes interactive sandboxes you can edit and run directly, so you can experiment with the patterns rather than just reading about them.
If you're looking for more on how these hooks fit into the bigger picture of React 19, check out React Concurrent Features: An Overview.
Sources:
Get the latest news and updates on developer certifications. Content is updated regularly, so please make sure to bookmark this page or sign up to get the latest content directly in your inbox.

React Docs Refresh: useActionState and useOptimistic
The React docs for useActionState and useOptimistic have been rewritten with clearer naming, new interactive sandboxes, and patterns from simple pending states to shopping carts with error recovery. Here's what changed and why it matters.
Aurora Scharff
Feb 24, 2026

JavaScript Mistakes That Quietly Destroy Production Apps
Some JavaScript mistakes don’t crash your app, they slowly degrade performance, reliability, and user trust. Here are the ones that cost the most in production.
Martin Ferret
Feb 19, 2026

Build Stronger Engineering Standards For Your Team
Standardise engineering standards in an AI-accelerated environment. Certificates.dev for Teams adds a Team Dashboard, reporting, and procurement-friendly purchasing.
Kristen Abrahams
Feb 19, 2026
We can help you recruit Certified Developers for your organization or project. The team has helped many customers employ suitable resources from a pool of 100s of qualified Developers.
Let us help you get the resources you need.
