useTransition lets you mark a state update as a non-urgent transition so React keeps the interface responsive while rendering heavy views. Calling useTransition() returns [isPending, startTransition], giving you a built-in loading flag (isPending) without manually managing extra boolean state.
If switching to a "Reports" tab renders thousands of rows, normal setTab('reports') blocks the main thread until rendering completes. Wrapping setTab('reports') inside startTransition lets the user click away to a different tab mid-render without waiting.
import { useState, useTransition } from 'react';
export function WorkspaceTabs() {
const [tab, setTab] = useState('overview');
const [isPending, startTransition] = useTransition();
function selectTab(nextTab) {
startTransition(() => {
setTab(nextTab);
});
}
return (
<section>
<div className="tab-bar">
<button type="button" onClick={() => selectTab('overview')}>Overview</button>
<button type="button" onClick={() => selectTab('analytics')}>Analytics</button>
{isPending && <span> Loading tab...</span>}
</div>
<div className="tab-content">
{tab === 'overview' ? <p>Quick summary view</p> : <p>Heavy analytics chart view</p>}
</div>
</section>
);
}
startTransitionIn React 19, startTransition also supports async functions. Calling an async save request inside startTransition(async () => { await saveProfile(); }) automatically keeps isPending set to true until the async action finishes.
useTransition MistakesstartTransition: Typing into <input value={text} onChange={...} /> must stay synchronous and urgent. Never put setText inside startTransition or keystrokes will lag and drop characters.startTransition Inside setTimeout Without Scope (React 18): In React 18, state setters inside await or setTimeout lost transition tracking unless wrapped inside another startTransition. React 19 handles async transitions natively.useTransition and startTransition?useTransition() is a Hook that returns [isPending, startTransition]. The standalone startTransition import works outside components (such as inside router stores) when you do not need isPending.
isPending block user clicks while true?No. In fact, the whole point of useTransition is letting users click another button or type while the pending transition runs in the background.
setState call use useTransition?No. Use it specifically for tab switches, route transitions, async actions, or expensive view updates that would otherwise block user interaction.
Sign in to track your learning journey, earn industry-recognized certificates, and join our elite developer community.
Quick Access With