Skip to main content

What are "Transition Updates"?

What Transition Updates are

A Transition Update is a low-priority state update that React can run later, pause, or cancel, if more important (urgent) user actions are happening right now.

In simpler terms:

Transitions = updates that can be deferred, so they don't get in the way of a fast UI response.


1. The problem Transitions solve

Before React 18, all calls to setState() were equal: React ran all updates with the same priority.

Example:

The user types text, and every keystroke filters a huge list:

javascript
function Search() { const [query, setQuery] = useState(''); const [results, setResults] = useState([]); function handleChange(e) { const value = e.target.value; setQuery(value); setResults(filterBigList(value)); // heavy update } return ( <> <input value={query} onChange={handleChange} /> <ResultsList items={results} /> </> ); }

In React 17 the UI can "lag": the input freezes while React renders the list.


2. How React 18 solves this with Transition Updates

Now you can mark part of the updates as not urgent (transitions):

javascript
import { useTransition } from 'react'; function Search() { const [query, setQuery] = useState(''); const [results, setResults] = useState([]); const [isPending, startTransition] = useTransition(); function handleChange(e) { const value = e.target.value; setQuery(value); // urgent update (typing) startTransition(() => { setResults(filterBigList(value)); // deferred (heavy) update }); } return ( <> <input value={query} onChange={handleChange} /> {isPending && <Spinner />} {/* while waiting */} <ResultsList items={results} /> </> ); }

Now:

  • the input field updates instantly;
  • React defers filtering the list;
  • you can show a loading indicator isPending while the Transition is not yet finished.

3. What startTransition() does under the hood

  1. React receives the function passed into startTransition();
  2. it marks the updates inside as low priority;
  3. if urgent updates arrive in the meantime (for example, keystrokes) - React pauses the Transition so the interface doesn't "freeze";
  4. as soon as the pipeline is free, React resumes the Transition.

4. "Urgent" vs "Transition" updates

Update typeExamplePriorityCan it be interrupted?Example API
UrgentTyping, clicks, focus, navigationHighNosetState() directly
Transition (deferred)Filtering, sorting, loading dataLowYesstartTransition() / useTransition()

React now understands the difference between what's UX-critical and what's resource-heavy.


5. How React decides what to render first

  • React works with two update queues:
    • urgent (input, focus, scroll, etc.);
    • deferred (transitions).
  • If the user is typing, urgent updates go through immediately.
  • React can:
    • defer any transition until the next frame;
    • pause it if the user keeps typing;
    • cancel it if new data arrives;
    • run it again, once the user has stopped.

6. An example with the isPending indicator

useTransition() returns:

  • isPending - a flag indicating that a Transition is currently running;
  • startTransition(callback) - a function to start low-priority updates.
javascript
const [isPending, startTransition] = useTransition(); startTransition(() => { setSearchResults(fetchFilteredResults(query)); });

When React pauses the render, isPending = true - you can show a spinner, a skeleton, or "Loading…" text.


7. React manages Transitions itself

Transitions only work when Concurrent Rendering is active, that is, when the application's root is created via:

javascript
import { createRoot } from 'react-dom/client'; const root = createRoot(document.getElementById('root')); root.render(<App />);

If you use the old ReactDOM.render(), startTransition simply has no effect - React cannot pause the render.


8. An example with asynchronous actions

javascript
function Products() { const [filter, setFilter] = useState('all'); const [data, setData] = useState([]); const [isPending, startTransition] = useTransition(); const handleFilter = (newFilter) => { startTransition(async () => { const res = await fetch(`/api/products?filter=${newFilter}`); const data = await res.json(); setData(data); setFilter(newFilter); }); }; return ( <> <Filters onChange={handleFilter} /> {isPending && <Skeleton />} <ProductList items={data} /> </> ); }

The UI stays responsive, even if the API request takes time.


9. What's new in React 19

React 19 improved Transitions - now startTransition() can be asynchronous:

javascript
await startTransition(async () => { await someAsyncOperation(); });

There is no longer a need to manually manage the pending state - React itself knows when the Transition is done.


Summary

Transition Updates are state updates that React runs smoothly, asynchronously, and without UI lag, deferring them while the user is interacting with the UI.


A quick comparison

CharacteristicRegular setStateTransition Update
PriorityHighLow
Can be interruptedNoYes
UI delayPossible (lag)None
Main useUI events (typing, clicks)Long computations, filters, loading
APIsetState()useTransition() / startTransition()

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.