How to fix useDeferredValue must be called at the top level of a component in React

ReactINTERMEDIATEMEDIUMUpdated Dec 9, 2025· 88 views

React throws this error when useDeferredValue is called inside a conditional statement, loop, or nested function. All hooks must be called in the same order on every render to maintain state consistency.

Quick fix

Fixes useDeferredValue must be called at the top level of a component

function SearchResults({ query, showDeferred }) {
  // ❌ Conditional hook call
  if (showDeferred) {
    const deferredQuery = useDeferredValue(query);
    return <Results query={deferredQuery} />;
  }
  return <Results query={query} />;
}
  1. Move useDeferredValue to the top level of your component
  2. Extract conditional logic to separate components if needed
  3. Remove useDeferredValue from loops and callbacks
  4. Ensure hooks are called before any early returns
react — error
function SearchResults({ query, showDeferred }) {
// ❌ Conditional hook call
if (showDeferred) {
const deferredQuery = useDeferredValue(query);
return <Results query={deferredQuery} />;
}
return <Results query={query} />;
}
useDeferredValue must be called at the top level of a component

What this error means

This error occurs when you violate React's Rules of Hooks by calling useDeferredValue conditionally or inside loops, nested functions, or after early returns. React hooks rely on a stable call order to correctly associate hook state with component instances across renders. The useDeferredValue hook, introduced in React 18, must follow the same rules as all other hooks: it must be called at the top level of your component function, before any conditional returns or branching logic. When hooks are called conditionally, React cannot guarantee they'll execute in the same order on every render, breaking the internal state management system. This restriction applies to all React hooks (useState, useEffect, useCallback, useDeferredValue, etc.) and is enforced by React's hook dispatcher, which tracks hook calls by their position in the call sequence rather than by name or identifier.

Typical symptoms

  • Error message: "useDeferredValue must be called at the top level of a component"
  • Error message: "React Hook useDeferredValue is called conditionally"
  • Component fails to render when conditional logic changes
  • ESLint warning: "React Hook is called conditionally" (if eslint-plugin-react-hooks is enabled)
  • Application crashes or shows blank screen in development mode
  • Inconsistent behavior when component re-renders with different props

Common causes

  1. Calling useDeferredValue inside an if/else statement or ternary operator
  2. Placing useDeferredValue inside a loop (for, while, map, etc.)
  3. Using useDeferredValue in a nested function or callback
  4. Calling useDeferredValue after an early return statement
  5. Conditionally importing and calling useDeferredValue based on feature flags
  6. Wrapping useDeferredValue in a try/catch block that might skip execution

How to fix "useDeferredValue must be called at the top level of a component"

1Move useDeferredValue to the top level of your component

Move the useDeferredValue call to the top of your component function, before any conditional logic or early returns:

Before (incorrect):

tsx
function SearchResults({ query, showDeferred }) {
  // ❌ Conditional hook call
  if (showDeferred) {
    const deferredQuery = useDeferredValue(query);
    return <Results query={deferredQuery} />;
  }
  return <Results query={query} />;
}

After (correct):

tsx
function SearchResults({ query, showDeferred }) {
  // ✅ Hook at top level, always called
  const deferredQuery = useDeferredValue(query);

  const displayQuery = showDeferred ? deferredQuery : query;
  return <Results query={displayQuery} />;
}

The key is to always call the hook, then use conditional logic to determine which value to use in your JSX.

2Extract conditional logic to separate components if needed

If you need different hook behavior based on conditions, split into separate components where each calls hooks unconditionally:

Before (incorrect):

tsx
function DataDisplay({ mode, value }) {
  if (mode === 'deferred') {
    const deferredValue = useDeferredValue(value); // ❌ Conditional
    return <div>{deferredValue}</div>;
  }
  return <div>{value}</div>;
}

After (correct):

tsx
function DeferredDisplay({ value }) {
  const deferredValue = useDeferredValue(value); // ✅ Top level
  return <div>{deferredValue}</div>;
}

function ImmediateDisplay({ value }) {
  return <div>{value}</div>;
}

function DataDisplay({ mode, value }) {
  // Conditional rendering, not conditional hooks
  return mode === 'deferred'
    ? <DeferredDisplay value={value} />
    : <ImmediateDisplay value={value} />;
}
3Remove useDeferredValue from loops and callbacks

Never call useDeferredValue inside map, forEach, or callback functions. Instead, call it once at the top level:

Before (incorrect):

tsx
function ListWithDeferredItems({ items }) {
  return (
    <ul>
      {items.map(item => {
        const deferred = useDeferredValue(item.value); // ❌ Inside loop
        return <li key={item.id}>{deferred}</li>;
      })}
    </ul>
  );
}

After (correct):

tsx
function DeferredItem({ value }) {
  const deferred = useDeferredValue(value); // ✅ Top level in component
  return <li>{deferred}</li>;
}

function ListWithDeferredItems({ items }) {
  return (
    <ul>
      {items.map(item => (
        <DeferredItem key={item.id} value={item.value} />
      ))}
    </ul>
  );
}
4Ensure hooks are called before any early returns

All hook calls must happen before any conditional return statements:

Before (incorrect):

tsx
function Search({ query, enabled }) {
  if (!enabled) return null; // ❌ Early return

  const deferredQuery = useDeferredValue(query); // Hook after return
  return <Results query={deferredQuery} />;
}

After (correct):

tsx
function Search({ query, enabled }) {
  const deferredQuery = useDeferredValue(query); // ✅ Before return

  if (!enabled) return null;
  return <Results query={deferredQuery} />;
}
5Enable ESLint rule to catch violations automatically

Install and configure eslint-plugin-react-hooks to catch Rules of Hooks violations during development:

bash
npm install --save-dev eslint-plugin-react-hooks

Add to your ESLint config (.eslintrc.json):

json
{
  "plugins": ["react-hooks"],
  "rules": {
    "react-hooks/rules-of-hooks": "error",
    "react-hooks/exhaustive-deps": "warn"
  }
}

This will show errors in your IDE and during linting when hooks are called conditionally.

Advanced notes

Why React enforces hook call order:

React doesn't use hook names or variables to track state - it uses the order hooks are called. Each hook call gets assigned an index (0, 1, 2, etc.) during the first render. On subsequent renders, React matches hooks to their previous state by index. If you call hooks conditionally, the order changes, causing React to assign state to the wrong hooks.

Alternative patterns for conditional deferred values:

If you truly need to conditionally apply deferred behavior, use this pattern:

tsx
function ConditionalDeferred({ value, shouldDefer }) {
  const deferredValue = useDeferredValue(value);
  // Always call hook, decide which value to use
  const finalValue = shouldDefer ? deferredValue : value;
  return <Display value={finalValue} />;
}

useDeferredValue vs useTransition:

Both hooks help manage concurrent rendering, but useDeferredValue is better when you need to defer a value you receive from props or state, while useTransition is better when you control the state update itself. Neither can be called conditionally.

TypeScript and hook violations:

TypeScript cannot catch Rules of Hooks violations at compile time because they're runtime constraints. Always use the ESLint plugin for static analysis.

Performance implications:

Calling useDeferredValue unconditionally doesn't hurt performance - React will only create a deferred version when needed. The overhead of always calling the hook is negligible compared to the alternative of violating hook rules.

Frequently asked questions

What does "useDeferredValue must be called at the top level of a component" mean?
This error occurs when you violate React's Rules of Hooks by calling useDeferredValue conditionally or inside loops, nested functions, or after early returns. React hooks rely on a stable call order to correctly associate hook state with component instances across renders. The useDeferredValue hook, introduced in React 18, must follow the same rules as all other hooks: it must be called at the top level of your component function, before any conditional returns or branching logic.
How do I fix "useDeferredValue must be called at the top level of a component"?
React throws this error when useDeferredValue is called inside a conditional statement, loop, or nested function. All hooks must be called in the same order on every render to maintain state consistency.
What causes "useDeferredValue must be called at the top level of a component"?
Calling useDeferredValue inside an if/else statement or ternary operator Placing useDeferredValue inside a loop (for, while, map, etc.) Using useDeferredValue in a nested function or callback
Is the "useDeferredValue must be called at the top level of a component" error serious?
It is a medium-severity error — more of a blocker than a risk. The steps above resolve it.

Official resources & further reading