React useTransition — Keeping UI Responsive During Heavy Updates
Learn how to use useTransition to keep your UI responsive during expensive state updates. Covers tab switching, filtering, navigation transitions, and the isPending flag.
Transition Hooks
Detailed Explanation
Responsive UI with useTransition
useTransition marks state updates as non-urgent transitions, allowing React to interrupt them to keep the UI responsive for higher-priority updates like typing.
The Problem
When switching tabs or filtering large lists, a heavy render can freeze the entire UI:
// Without useTransition -- UI freezes while rendering 10000 items
function handleTabChange(tab: string) {
setTab(tab); // Blocks the UI until the render completes
}
The Solution
const [isPending, startTransition] = useTransition();
function handleTabChange(tab: string) {
startTransition(() => {
setTab(tab); // Non-urgent -- React can interrupt this
});
}
return (
<>
{isPending && <Spinner />}
<TabContent tab={tab} />
</>
);
How It Works
- React starts rendering the transition update
- If a higher-priority update arrives (e.g., user types in an input), React pauses the transition
- React renders the urgent update immediately
- React resumes the transition when the main thread is free
isPendingis true while the transition render is in progress
Tab Switching Pattern
function TabContainer() {
const [tab, setTab] = useState("home");
const [isPending, startTransition] = useTransition();
function selectTab(nextTab: string) {
startTransition(() => setTab(nextTab));
}
return (
<div>
<nav style={{ opacity: isPending ? 0.7 : 1 }}>
{["home", "posts", "settings"].map(t => (
<button key={t} onClick={() => selectTab(t)}>
{t}
</button>
))}
</nav>
<TabContent tab={tab} />
</div>
);
}
Key Constraints
- The callback passed to
startTransitionmust be synchronous - It only wraps state updates -- not async operations directly
- Keep input state that controls typing outside the transition
Use Case
Use useTransition for tab switching with expensive child rendering, navigation transitions, filtering large lists without blocking input, and any UI update that can tolerate being interrupted.