useTransition

Mark a State Update as Non-Urgent

useTransition

`useTransition` lets you flag a state update as low-priority. The UI keeps responding to fast user input while the slow update happens in the background.

4 min read Level 3/5 #react#useTransition#concurrent
What you'll learn
  • Wrap slow updates in `startTransition`
  • Read `isPending` to show a subtle loading hint

useTransition returns [isPending, startTransition]. Calls inside startTransition are marked low-priority. React keeps the UI responsive — clicking a different button, typing, or scrolling gets handled first.

The Shape

function Tabs() {
  const [tab, setTab] = useState("home");
  const [isPending, startTransition] = useTransition();

  function selectTab(next) {
    startTransition(() => {
      setTab(next);   // tagged as non-urgent
    });
  }

  return (
    <>
      <button onClick={() => selectTab("home")}>Home</button>
      <button onClick={() => selectTab("dashboard")}>Dashboard</button>
      {isPending && <Spinner />}
      <TabPanel tab={tab} />
    </>
  );
}

If <TabPanel tab="dashboard"> renders a heavy chart, the user can still click other tabs without waiting. isPending is true while the heavy render is in flight — perfect for a subtle loading hint.

When To Use

  • A click triggers an expensive list re-render
  • Switching tabs renders something heavy
  • A filter or sort produces a slow result

If the update is fast, you don’t need transitions. If it’s slow, transitions keep input snappy at the cost of a slight delay applying the change.

useTransition vs useDeferredValue

HookWhere it livesWhat it defers
useTransitionWhere you trigger the updateA specific setX call
useDeferredValueWhere the slow render reads a valueA specific value’s identity

Both achieve the same kind of “urgent vs background” split — pick the one that fits the place you can change.

Caveats

  • Transitions can run more than once if React decides to abandon and restart the slow work. The reducer / setter you call has to be safe to run multiple times — pure, no side effects.
  • Don’t put fetches inside startTransition. It only helps with CPU-bound rendering, not network I/O.

Up Next

A specialized hook for subscribing to state that lives outside React — third-party stores, browser APIs.

useSyncExternalStore →