Skip to main content

What does startTransition() do?

In short: what startTransition() does

startTransition() tells React that the updates inside it are not urgent, and they can be deferred, paused, or canceled, so the interface stays instantly responsive to the user.

Put simply:

"Do the important things (typing, clicks) now, and the heavy ones later, when there's time."


1. The problem without startTransition()

Before React 18, every setState() call had the same priority. If the UI performed a heavy operation (for example, filtering a large list), the interface could freeze up until React finished rendering.

Example without startTransition():

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

The problem: while typing, React renders the list on every character, the input field lags behind.


2. The solution: startTransition()

React 18 lets you mark a "heavy" update as low priority:

javascript
import { startTransition } from 'react'; function handleChange(e) { const value = e.target.value; setQuery(value); // urgent (high priority) startTransition(() => { setResults(filterBigList(value)); // deferred (low priority) }); }

Now:

  • React updates the input instantly (high priority);
  • the "list render" happens later, when the thread is free;
  • if the user keeps typing, React cancels the old filtering and starts a new one.

3. How it works internally

When React sees startTransition(callback):

  1. React puts the updates inside the callback into a separate queue - the "transitions" queue (low priority);
  2. All regular setState() calls outside startTransition stay urgent;
  3. React runs the urgent tasks first (for example, text input);
  4. Then, when the thread is free, React resumes the transition;
  5. If a new urgent update arrives in the meantime, React interrupts the transition and starts a new one (so the interface stays always up to date).

4. Syntax and usage

In a function component:

javascript
import { startTransition } from 'react'; startTransition(() => { setState(...); // any low-priority update });

Or through the hook:

javascript
const [isPending, startTransition] = useTransition();

(this version also lets you track the pending status, isPending)


5. Example with isPending (via useTransition)

javascript
function Search() { const [query, setQuery] = useState(''); const [results, setResults] = useState([]); const [isPending, startTransition] = useTransition(); function handleChange(e) { const value = e.target.value; setQuery(value); startTransition(() => { setResults(filterBigList(value)); }); } return ( <> <input value={query} onChange={handleChange} /> {isPending && <span>Updating list...</span>} <ResultsList items={results} /> </> ); }

Behavior:

  • setQuery() updates the field immediately;
  • setResults() renders asynchronously;
  • isPending shows an indicator until the transition finishes.

6. The difference between a regular update and a transition

CharacteristicRegular update (setState)Transition (startTransition)
PriorityHigh (urgent)Low (deferred)
Can be interruptedNoYes
When it runsImmediatelyWhen there's free time
Used forInput, clicks, animationsFiltering, loading, rebuilding the UI
Effect on UXCan lagSmooth UI

7. React decides the priorities itself

React splits all updates into two types:

  • Urgent - come from user actions (typing, clicking);
  • Transition - less important, can run later.

React runs urgent events immediately, and transitions in the background, without blocking the interface.


8. What's new in React 19

In React 19, startTransition() started understanding async/await: now you can wait for async operations inside a Transition to finish.

javascript
await startTransition(async () => { const data = await fetch('/api/products').then(res => res.json()); setProducts(data); });

Before (in React 18), startTransition() only accepted a synchronous function - async code had to be wrapped manually.


9. When to use startTransition()

Use startTransition() for:

  • filtering / sorting / searching a large list;
  • loading data after an interaction;
  • switching tabs or routes, if it requires rendering a large tree;
  • updates that are not critical to instant UX.

Don't use it for:

  • click / focus / input events, they must be urgent;
  • small UI updates (icons, loaders, etc.).

Summary

startTransition() is a way to mark state updates as low priority.

React runs them asynchronously and smoothly, so the UI doesn't freeze.

It's ideal for "heavy" or non-urgent interface changes.


Quick cheat sheet

What it doesKey idea
startTransition(callback)Marks updates as "non-urgent"
Does it "freeze" the UI?No, the UI stays responsive
Can it be canceled / pausedYes
Works only in Concurrent ModeYes (createRoot())
Returns a Promise (in React 19+)Yes
Typical scenariosFiltering, navigation, sorting, loading data

Short Answer

Interview ready
Premium

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