useDeferredValue takes a value and gives you a 'late' version. The input stays urgent. The expensive render reads the late version and lags slightly. The result: typing feels instant; results catch up.
The shape
const deferred = useDeferredValue(value). deferred equals value initially, then equals the previous value during high-priority renders (typing) while the new render with the new value is in progress in the background. When the background render finishes, deferred updates and the heavy subtree re-renders with the new value.
useDeferredValue vs useTransition
Both achieve similar UX. The difference is who owns the value:
- useTransition — you own the state, you wrap the update in
startTransition. - useDeferredValue — the value comes from somewhere you don't control (a prop, a context). You can't wrap the update, but you can mark the value as deferrable.
Inside a component you control: useTransition. Receiving a prop: useDeferredValue.
Pairing with React.memo
useDeferredValue only helps if the expensive child can skip re-rendering when its props haven't changed. Wrap the child in React.memo (or trust the Compiler to memoize it). Without memoization, the deferred value still triggers a re-render every time, and you lose the benefit.