Lesson 37 of 80
The Fiber lesson shows startTransition in passing to prove renders can be interrupted. This lesson is the hook itself — what isPending gives you, and where marking an update non-urgent actually helps versus just adds noise.
14 min read
Every option explains itself — why the right one is right, and why each wrong one is wrong. Miss one and it comes back later on a spaced-repetition schedule.
This topic is about judgment and practical tradeoffs more than a single right answer — a mock interview is the better way to test yourself on it.
Be interviewed on this →Hints without spoilers, and a plain explanation of why a wrong answer was wrong — answered only from this lesson. Free account, no card.
Sign up freeWhat interviewers actually ask about this, and what a strong answer has to cover.
A strong answer covers
Likely follow-ups
Not every state update needs to happen with the same priority. Typing into a search box should feel instant — the input has to reflect every keystroke immediately, no exceptions. But if that keystroke also triggers filtering ten thousand rows, the filtering doesn't need to happen before the input updates — it just needs to happen soon. useTransition is how you tell React that distinction explicitly: this state update is allowed to be interrupted, delayed, or thrown away and restarted, because something else is more urgent.
const [isPending, startTransition] = useTransition() gives you two things. startTransition(fn) wraps a state update and marks it low-priority. isPending tells you, without any manual flag of your own, whether that low-priority work is still catching up — so you can show a loading indicator without wiring up your own boolean.
function ProductSearch({ allProducts }) {
const [query, setQuery] = useState("");
const [results, setResults] = useState(allProducts);
const [isPending, startTransition] = useTransition();
function handleChange(e) {
const next = e.target.value;
setQuery(next); // urgent — the input must reflect every keystroke immediately
startTransition(() => {
// non-urgent — can be interrupted by the next keystroke without ever finishing
setResults(allProducts.filter((p) => p.name.includes(next)));
});
}
return (
<>
<input value={query} onChange={handleChange} />
<ul style={{ opacity: isPending ? 0.5 : 1 }}>
{results.map((p) => <li key={p.id}>{p.name}</li>)}
</ul>
</>
);
}
setQuery runs outside startTransition, so the input's value updates on every keystroke with no delay — that's non-negotiable for feeling responsive. setResults runs inside startTransition: if the user types a second character before the filter over ten thousand products finishes, React abandons that in-progress low-priority render entirely and starts fresh with the latest query, rather than finishing a now-stale filter first and showing results for a query that's already gone. isPending dims the list while that catch-up is happening, with zero manual bookkeeping.
useTransition doesn't make the filtering computation any faster — it changes when and whether that computation's result gets shown, letting more urgent updates cut in line. If the underlying work is genuinely slow, useTransition doesn't fix that; it just stops it from blocking the input.useDeferredValue solves a closely related problem from the other end. Instead of marking the update as low priority, it lets a value lag behind the latest render — useful when you don't control the code setting the state (a value coming from a prop or a library) and can't wrap the update in startTransition yourself.startTransition must be state updates, not arbitrary async work. Wrapping a fetch call directly in startTransition doesn't mark the eventual response as low-priority — only the state-setting call itself is what React tracks as part of the transition.The Fiber lesson explains the mechanism that makes any of this possible — reconciliation restructured so React can pause, abandon, and resume a render instead of running it start-to-finish uninterrupted — and uses startTransition briefly just to prove that capability exists. This lesson is the follow-through: the actual hook, what isPending buys you day to day, and the concrete judgment call of which state updates in a real component are worth marking non-urgent in the first place.