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():
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:
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):
- React puts the updates inside the callback into a separate queue - the "transitions" queue (low priority);
- All regular
setState()calls outsidestartTransitionstay urgent; - React runs the urgent tasks first (for example, text input);
- Then, when the thread is free, React resumes the transition;
- 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:
import { startTransition } from 'react';
startTransition(() => {
setState(...); // any low-priority update
});Or through the hook:
const [isPending, startTransition] = useTransition();(this version also lets you track the pending status, isPending)
5. Example with isPending (via useTransition)
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;isPendingshows an indicator until the transition finishes.
6. The difference between a regular update and a transition
| Characteristic | Regular update (setState) | Transition (startTransition) |
|---|---|---|
| Priority | High (urgent) | Low (deferred) |
| Can be interrupted | No | Yes |
| When it runs | Immediately | When there's free time |
| Used for | Input, clicks, animations | Filtering, loading, rebuilding the UI |
| Effect on UX | Can lag | Smooth 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.
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 does | Key idea |
|---|---|
startTransition(callback) | Marks updates as "non-urgent" |
| Does it "freeze" the UI? | No, the UI stays responsive |
| Can it be canceled / paused | Yes |
| Works only in Concurrent Mode | Yes (createRoot()) |
Returns a Promise (in React 19+) | Yes |
| Typical scenarios | Filtering, navigation, sorting, loading data |
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.