useTransition & useDeferredValue
Keep the UI responsive during heavy updates by marking work as non-urgent
Some state updates are urgent (typing in an input) and some are expensive (filtering 10,000 rows). If you treat them the same, typing stutters. React's concurrent features let you mark the expensive work as non-urgent so the urgent work stays smooth.
Two Speeds of Update
React 19 treats updates as either urgent (must feel instant — keystrokes, clicks) or transitions (can lag slightly — rendering big results). Marking heavy updates as transitions lets React interrupt them to keep urgent updates responsive.
useTransition
useTransition gives you a startTransition function and an isPending flag:
const [isPending, startTransition] = useTransition()
function handleChange(value: string) {
setQuery(value) // urgent — input stays snappy
startTransition(() => {
setFilter(value) // non-urgent — the heavy re-render
})
}
The setQuery update applies immediately so the input never lags. The setFilter update — which triggers the expensive list render — runs as a transition React can interrupt. isPending is true while it's catching up, perfect for a subtle spinner.
useDeferredValue
useDeferredValue is the value-based sibling. Instead of wrapping a setter, you defer a value — React gives you a copy that lags behind during heavy work:
const deferredQuery = useDeferredValue(query)
// Pass deferredQuery (not query) to the expensive computation.
const results = useMemo(() => filter(deferredQuery), [deferredQuery])
query updates instantly (input stays fast); deferredQuery catches up when React has spare time. Compare query !== deferredQuery to know the results are stale and dim them.
Use useTransition when you control the state update (you call
the setter). Use useDeferredValue when the value comes from
props or you can't wrap the update — e.g. deferring a search term passed
down from a parent.
Try It Live
Type quickly into this filter over 8,000 items. The input stays responsive while the list lags behind and dims — that gap is the transition at work:
- Item 0 — widget component
- Item 1 — widget component
- Item 2 — widget component
- Item 3 — widget component
- Item 4 — widget component
- Item 5 — widget component
- Item 6 — widget component
- Item 7 — widget component
- Item 8 — widget component
- Item 9 — widget component
- Item 10 — widget component
- Item 11 — widget component
- Item 12 — widget component
- Item 13 — widget component
- Item 14 — widget component
- Item 15 — widget component
- Item 16 — widget component
- Item 17 — widget component
- Item 18 — widget component
- Item 19 — widget component
- Item 20 — widget component
- Item 21 — widget component
- Item 22 — widget component
- Item 23 — widget component
- Item 24 — widget component
- Item 25 — widget component
- Item 26 — widget component
- Item 27 — widget component
- Item 28 — widget component
- Item 29 — widget component
- Item 30 — widget component
- Item 31 — widget component
- Item 32 — widget component
- Item 33 — widget component
- Item 34 — widget component
- Item 35 — widget component
- Item 36 — widget component
- Item 37 — widget component
- Item 38 — widget component
- Item 39 — widget component
- Item 40 — widget component
- Item 41 — widget component
- Item 42 — widget component
- Item 43 — widget component
- Item 44 — widget component
- Item 45 — widget component
- Item 46 — widget component
- Item 47 — widget component
- Item 48 — widget component
- Item 49 — widget component
- Item 50 — widget component
- Item 51 — widget component
- Item 52 — widget component
- Item 53 — widget component
- Item 54 — widget component
- Item 55 — widget component
- Item 56 — widget component
- Item 57 — widget component
- Item 58 — widget component
- Item 59 — widget component
- Item 60 — widget component
- Item 61 — widget component
- Item 62 — widget component
- Item 63 — widget component
- Item 64 — widget component
- Item 65 — widget component
- Item 66 — widget component
- Item 67 — widget component
- Item 68 — widget component
- Item 69 — widget component
- Item 70 — widget component
- Item 71 — widget component
- Item 72 — widget component
- Item 73 — widget component
- Item 74 — widget component
- Item 75 — widget component
- Item 76 — widget component
- Item 77 — widget component
- Item 78 — widget component
- Item 79 — widget component
- Item 80 — widget component
- Item 81 — widget component
- Item 82 — widget component
- Item 83 — widget component
- Item 84 — widget component
- Item 85 — widget component
- Item 86 — widget component
- Item 87 — widget component
- Item 88 — widget component
- Item 89 — widget component
- Item 90 — widget component
- Item 91 — widget component
- Item 92 — widget component
- Item 93 — widget component
- Item 94 — widget component
- Item 95 — widget component
- Item 96 — widget component
- Item 97 — widget component
- Item 98 — widget component
- Item 99 — widget component
The input stays responsive while the list lags behind and dims — that gap is the transition keeping typing urgent and filtering deferred.
They make it non-blocking. The expensive render still happens — but React prioritizes urgent updates first, so the app never feels frozen. For genuinely huge lists, also virtualize.