useDeferredValue: Deferring UI Updates

+15 Mana ✨

useDeferredValue lets you defer updating a part of the UI. It's like debouncing, but integrated with React's rendering.

Basic Usage

tsx
function SearchResults({ query }: { query: string }) {
  // deferredQuery lags behind query during typing
  const deferredQuery = useDeferredValue(query);
  const isStale = query !== deferredQuery;

  return (
    <div style={{ opacity: isStale ? 0.5 : 1 }}>
      <Results query={deferredQuery} />
    </div>
  );
}

How It Differs from useTransition

AspectuseTransitionuseDeferredValue
ControlsState updateValue
Use whenYou control the stateValue comes from props
Returns[isPending, startTransition]Deferred value

When to Use useDeferredValue

  1. Props from parent - when you can't wrap the state update
  2. Third-party components - when you don't control the state
  3. URL-driven state - query params, etc.

Example: Search with External State

tsx
// Parent controls the query state
function SearchPage() {
  const [query, setQuery] = useState('');

  return (
    <>
      <SearchInput value={query} onChange={setQuery} />
      <SearchResults query={query} />
    </>
  );
}

// Child defers the expensive render
function SearchResults({ query }: { query: string }) {
  const deferredQuery = useDeferredValue(query);
  
  // Memoize to actually skip re-rendering with stale value
  const results = useMemo(
    () => <SlowList query={deferredQuery} />,
    [deferredQuery]
  );

  return (
    <div style={{ opacity: query !== deferredQuery ? 0.7 : 1 }}>
      {results}
    </div>
  );
}

Combining with Suspense

tsx
function App() {
  const [query, setQuery] = useState('');
  const deferredQuery = useDeferredValue(query);

  return (
    <>
      <input
        value={query}
        onChange={(e) => setQuery(e.target.value)}
      />
      <Suspense fallback={<Loading />}>
        <SearchResults query={deferredQuery} />
      </Suspense>
    </>
  );
}

When query changes:

  1. Input updates immediately (responsive typing)
  2. deferredQuery keeps the old value briefly
  3. React renders with the new deferredQuery in the background
  4. Once ready, React commits the new UI
✓ Completed