How to fix startTransition cannot be called during render in React

ReactINTERMEDIATEMEDIUMUpdated Dec 9, 2025· 110 views

This error occurs when startTransition is called directly in the render phase instead of in event handlers or effects. React requires startTransition to be called during non-render phases to properly manage concurrent updates and maintain rendering stability.

Quick fix

Fixes startTransition cannot be called during render

// ❌ WRONG - calling during render
function SearchResults({ query }) {
  startTransition(() => {
    setSearchQuery(query);
  });

  return <div>...</div>;
}

// ✅ CORRECT - calling in event handler
function SearchResults() {
  const [searchQuery, setSearchQuery] = useState('');

  const handleSearch = (query: string) => {
    startTransition(() => {
      setSearchQuery(query);
    });
  };

  return (
    <input
      onChange={(e) => handleSearch(e.target.value)}
    />
  );
}
  1. Move startTransition to event handler
  2. Use useEffect for side effects
  3. Use useTransition hook for isPending state
  4. Verify React 18+ version
react — error
// ❌ WRONG - calling during render
function SearchResults({ query }) {
startTransition(() => {
setSearchQuery(query);
});
return <div>...</div>;
}
// ✅ CORRECT - calling in event handler
function SearchResults() {
const [searchQuery, setSearchQuery] = useState('');
const handleSearch = (query: string) => {
startTransition(() => {
setSearchQuery(query);
});
};
return (
<input
onChange={(e) => handleSearch(e.target.value)}
/>
);
}
startTransition cannot be called during render

What this error means

The "startTransition cannot be called during render" error is a React 18+ safeguard that prevents improper use of the Concurrent Features API. startTransition is designed to mark state updates as non-urgent transitions, allowing React to interrupt them for more urgent updates like user input. When you call startTransition during the render phase (directly in the component body), React cannot properly schedule and manage these transitions. The render phase must be pure and free of side effects - calling startTransition here violates this principle and can lead to unpredictable behavior, infinite loops, or rendering inconsistencies. This error typically appears in development mode as React actively checks for improper API usage. In production, it may manifest as unexpected rendering behavior or runtime errors.

Typical symptoms

  • Error message "startTransition cannot be called during render" appears in console
  • Components fail to render when attempting state updates
  • React DevTools shows errors during component execution
  • Application crashes or hangs when certain components mount
  • Warnings about improper hook usage in concurrent mode

Common causes

  1. Calling startTransition directly in component body during render phase
  2. Using startTransition inside conditional logic that runs during render
  3. Attempting to wrap state updates in startTransition within useMemo or useCallback dependencies
  4. Calling startTransition in server-side rendering context where it's not available
  5. Using startTransition synchronously with state setters during initial render

How to fix "startTransition cannot be called during render"

1Move startTransition to event handler

The most common fix is to move startTransition calls into event handlers rather than the render phase:

tsx
// ❌ WRONG - calling during render
function SearchResults({ query }) {
  startTransition(() => {
    setSearchQuery(query);
  });

  return <div>...</div>;
}

// ✅ CORRECT - calling in event handler
function SearchResults() {
  const [searchQuery, setSearchQuery] = useState('');

  const handleSearch = (query: string) => {
    startTransition(() => {
      setSearchQuery(query);
    });
  };

  return (
    <input
      onChange={(e) => handleSearch(e.target.value)}
    />
  );
}

This ensures startTransition only runs in response to user interactions, not during the render phase.

2Use useEffect for side effects

If you need to trigger transitions based on prop changes, use useEffect:

tsx
// ❌ WRONG - calling during render
function FilteredList({ filter }) {
  startTransition(() => {
    setFilteredItems(items.filter(item => item.matches(filter)));
  });

  return <List items={filteredItems} />;
}

// ✅ CORRECT - using useEffect
function FilteredList({ filter }) {
  const [filteredItems, setFilteredItems] = useState([]);

  useEffect(() => {
    startTransition(() => {
      setFilteredItems(items.filter(item => item.matches(filter)));
    });
  }, [filter]);

  return <List items={filteredItems} />;
}

This defers the transition until after the initial render completes.

3Use useTransition hook for isPending state

Replace standalone startTransition with the useTransition hook for better control:

tsx
import { useTransition } from 'react';

function SearchComponent() {
  const [isPending, startTransition] = useTransition();
  const [searchResults, setSearchResults] = useState([]);

  const handleSearch = (query: string) => {
    startTransition(() => {
      // This state update is now marked as a transition
      setSearchResults(performExpensiveSearch(query));
    });
  };

  return (
    <div>
      <input onChange={(e) => handleSearch(e.target.value)} />
      {isPending && <Spinner />}
      <Results data={searchResults} />
    </div>
  );
}

The useTransition hook provides the startTransition function along with a pending state indicator.

4Verify React 18+ version

Ensure you're using React 18 or higher with proper imports:

bash
# Check your React version
npm list react react-dom

# Upgrade if needed
npm install react@latest react-dom@latest

Then verify your imports:

tsx
import { startTransition } from 'react';
// or
import { useTransition } from 'react';

If you're on React 17 or earlier, startTransition is not available and you'll need to upgrade.

5Handle async operations properly

In React 18, startTransition callbacks must be synchronous. For async operations:

tsx
// ❌ WRONG - async function in React 18
const handleSubmit = () => {
  startTransition(async () => {
    const result = await fetchData();
    setData(result);
  });
};

// ✅ CORRECT - wrap only the state update
const handleSubmit = async () => {
  const result = await fetchData();

  startTransition(() => {
    setData(result);
  });
};

Note: React 19 supports async callbacks in startTransition, but React 18 requires synchronous functions.

Advanced notes

Concurrent Rendering Context: startTransition is part of React's Concurrent Features that enable interruptible rendering. When you mark updates as transitions, React can pause work on them to handle more urgent updates (like user input), then resume the transition. This requires strict control over when transitions start - allowing them during render would break React's ability to manage the update queue.

Server-Side Rendering: On the server, startTransition has no effect since SSR is always synchronous. If you see this error during SSR, it indicates code that should only run on the client is executing on the server. Use typeof window !== 'undefined' checks or ensure the code only runs in client components with the 'use client' directive.

useMemo and useCallback Gotcha: Never call startTransition inside useMemo or useCallback dependency arrays or during their execution on render:

tsx
// ❌ WRONG
const memoizedValue = useMemo(() => {
  startTransition(() => setCount(count + 1));
  return count * 2;
}, [count]);

// ✅ CORRECT
const handleIncrement = useCallback(() => {
  startTransition(() => setCount(count + 1));
}, [count]);

React 19 Changes: React 19 introduces async support for startTransition callbacks, allowing you to use await inside the transition function. This is a breaking change from React 18's synchronous-only requirement. If upgrading, review all startTransition usage to take advantage of this improvement.

Debugging Tips: Enable React DevTools Profiler with "Highlight updates when components render" to visualize when transitions occur. This helps identify if transitions are firing during render vs. in response to events.

Frequently asked questions

What does "startTransition cannot be called during render" mean?
The "startTransition cannot be called during render" error is a React 18+ safeguard that prevents improper use of the Concurrent Features API. startTransition is designed to mark state updates as non-urgent transitions, allowing React to interrupt them for more urgent updates like user input. When you call startTransition during the render phase (directly in the component body), React cannot properly schedule and manage these transitions.
How do I fix "startTransition cannot be called during render"?
This error occurs when startTransition is called directly in the render phase instead of in event handlers or effects. React requires startTransition to be called during non-render phases to properly manage concurrent updates and maintain rendering stability.
What causes "startTransition cannot be called during render"?
Calling startTransition directly in component body during render phase Using startTransition inside conditional logic that runs during render Attempting to wrap state updates in startTransition within useMemo or useCallback dependencies
Is the "startTransition cannot be called during render" error serious?
It is a medium-severity error — more of a blocker than a risk. The steps above resolve it.

Official resources & further reading