useTransition
Reference
useTransition()
Call useTransition
at the top level of your component to mark some state updates as Transitions.
Parameters
useTransition
does not take any parameters.
Returns
useTransition
returns an array with exactly two items:
- The
isPending
flag that tells you whether there is a pending Transition. - The that lets you mark updates as a Transition.
startTransition(action)
The startTransition
function returned by useTransition
lets you mark an update as a Transition.
Parameters
action
: A function that updates some state by calling one or more . React callsaction
immediately with no parameters and marks all state updates scheduled synchronously during theaction
function call as Transitions. Any async calls that are awaited in theaction
will be included in the Transition, but currently require wrapping anyset
functions after theawait
in an additionalstartTransition
(see ). State updates marked as Transitions will be and .
Returns
startTransition
does not return anything.
Caveats
useTransition
is a Hook, so it can only be called inside components or custom Hooks. If you need to start a Transition somewhere else (for example, from a data library), call the standalone instead.You can wrap an update into a Transition only if you have access to the
set
function of that state. If you want to start a Transition in response to some prop or a custom Hook value, try instead.The function you pass to
startTransition
is called immediately, marking all state updates that happen while it executes as Transitions. If you try to perform state updates in asetTimeout
, for example, they won’t be marked as Transitions.You must wrap any state updates after any async requests in another
startTransition
to mark them as Transitions. This is a known limitation that we will fix in the future (see ).The
startTransition
function has a stable identity, so you will often see it omitted from Effect dependencies, but including it will not cause the Effect to fire. If the linter lets you omit a dependency without errors, it is safe to do.A state update marked as a Transition will be interrupted by other state updates. For example, if you update a chart component inside a Transition, but then start typing into an input while the chart is in the middle of a re-render, React will restart the rendering work on the chart component after handling the input update.
Transition updates can’t be used to control text inputs.
If there are multiple ongoing Transitions, React currently batches them together. This is a limitation that may be removed in a future release.
Usage
Perform non-blocking updates with Actions
Call useTransition
at the top of your component to create Actions, and access the pending state:
useTransition
returns an array with exactly two items:
- The
isPending
flag that tells you whether there is a pending Transition. - The
startTransition
function that lets you create an Action.
To start a Transition, pass a function to startTransition
like this:
The function passed to startTransition
is called the “Action”. You can update state and (optionally) perform side effects within an Action, and the work will be done in the background without blocking user interactions on the page. A Transition can include multiple Actions, and while a Transition is in progress, your UI stays responsive. For example, if the user clicks a tab but then changes their mind and clicks another tab, the second click will be immediately handled without waiting for the first update to finish.
To give the user feedback about in-progress Transitions, the isPending
state switches to true
at the first call to startTransition
, and stays true
until all Actions complete and the final state is shown to the user. Transitions ensure side effects in Actions to complete in order to , and you can provide immediate feedback while the Transition is in progress with useOptimistic
.
Exposing action
prop from components
You can expose an action
prop from a component to allow a parent to call an Action.
For example, this TabButton
component wraps its onClick
logic in an action
prop:
Because the parent component updates its state inside the action
, that state update gets marked as a Transition. This means you can click on “Posts” and then immediately click “Contact” and it does not block user interactions:
Displaying a pending visual state
You can use the isPending
boolean value returned by useTransition
to indicate to the user that a Transition is in progress. For example, the tab button can have a special “pending” visual state:
Notice how clicking “Posts” now feels more responsive because the tab button itself updates right away:
Preventing unwanted loading indicators
In this example, the PostsTab
component fetches some data using . When you click the “Posts” tab, the PostsTab
component suspends, causing the closest loading fallback to appear:
Hiding the entire tab container to show a loading indicator leads to a jarring user experience. If you add useTransition
to TabButton
, you can instead display the pending state in the tab button instead.
Notice that clicking “Posts” no longer replaces the entire tab container with a spinner:
Building a Suspense-enabled router
If you’re building a React framework or a router, we recommend marking page navigations as Transitions.
This is recommended for three reasons:
- which lets the user click away without waiting for the re-render to complete.
- which lets the user avoid jarring jumps on navigation.
- which lets the user wait for side effects to complete before the new page is shown.
Here is a simplified router example using Transitions for navigations.
Displaying an error to users with an error boundary
If a function passed to startTransition
throws an error, you can display an error to your user with an . To use an error boundary, wrap the component where you are calling the useTransition
in an error boundary. Once the function passed to startTransition
errors, the fallback for the error boundary will be displayed.
Troubleshooting
Updating an input in a Transition doesn’t work
You can’t use a Transition for a state variable that controls an input:
This is because Transitions are non-blocking, but updating an input in response to the change event should happen synchronously. If you want to run a Transition in response to typing, you have two options:
- You can declare two separate state variables: one for the input state (which always updates synchronously), and one that you will update in a Transition. This lets you control the input using the synchronous state, and pass the Transition state variable (which will “lag behind” the input) to the rest of your rendering logic.
- Alternatively, you can have one state variable, and add which will “lag behind” the real value. It will trigger non-blocking re-renders to “catch up” with the new value automatically.
React doesn’t treat my state update as a Transition
When you wrap a state update in a Transition, make sure that it happens during the startTransition
call:
The function you pass to startTransition
must be synchronous. You can’t mark an update as a Transition like this:
Instead, you could do this:
React doesn’t treat my state update after await
as a Transition
When you use await
inside a startTransition
function, the state updates that happen after the await
are not marked as Transitions. You must wrap state updates after each await
in a startTransition
call:
However, this works instead:
This is a JavaScript limitation due to React losing the scope of the async context. In the future, when is available, this limitation will be removed.
I want to call useTransition
from outside a component
You can’t call useTransition
outside a component because it’s a Hook. In this case, use the standalone method instead. It works the same way, but it doesn’t provide the isPending
indicator.
The function I pass to startTransition
executes immediately
If you run this code, it will print 1, 2, 3:
It is expected to print 1, 2, 3. The function you pass to startTransition
does not get delayed. Unlike with the browser setTimeout
, it does not run the callback later. React executes your function immediately, but any state updates scheduled while it is running are marked as Transitions. You can imagine that it works like this:
My state updates in Transitions are out of order
If you await
inside startTransition
, you might see the updates happen out of order.
In this example, the updateQuantity
function simulates a request to the server to update the item’s quantity in the cart. This function artificially returns the every other request after the previous to simulate race conditions for network requests.
Try updating the quantity once, then update it quickly multiple times. You might see the incorrect total:
When clicking multiple times, it’s possible for previous requests to finish after later requests. When this happens, React currently has no way to know the intended order. This is because the updates are scheduled asynchronously, and React loses context of the order across the async boundary.
This is expected, because Actions within a Transition do not guarantee execution order. For common use cases, React provides higher-level abstractions like and that handle ordering for you. For advanced use cases, you’ll need to implement your own queuing and abort logic to handle this.
Example of useActionState
handling execution order: