Concurrency in React 18
How React 18 introduced interruptible rendering with useTransition and useDeferredValue to keep your app responsive during heavy updates.
The Synchronous Rendering Problem
Before React 18, rendering was entirely synchronous. Once React started rendering an update (like setting state), it could not stop until it was finished. It blocked the browser's main thread.
If you typed into a search input, and that search input triggered a heavy data visualization that took 500ms to render, your browser would freeze for 500ms. You couldn't even type the next letter.
React 18 introduced **Concurrent Rendering**. React can now pause a heavy render, handle an urgent user event (like typing or clicking), and then resume the heavy render later.
Urgent vs Non-Urgent Updates
Concurrency introduces the concept of priority. Not all state updates are equally important.
**Urgent updates** reflect direct interaction, like typing, clicking, or dragging. Users expect these to be instant. If they aren't, the app feels broken.
**Non-urgent updates** (Transitions) transition the UI from one view to another, like filtering a massive list or switching pages. Users are okay with a slight delay here, as long as the app doesn't completely freeze.
useTransition and useDeferredValue
React provides two main hooks to opt-in to concurrent features:
const [isPending, startTransition] = useTransition();
Wrap a non-urgent state update inside startTransition. React will process it in the background, keeping the main thread free. The isPending boolean lets you show a loading indicator.
Alternatively, use const deferredQuery = useDeferredValue(query);. This tells React to use the old value for a heavy component until the new value is ready to be rendered in the background.
The Main Thread Scheduler
Compare what happens when a user types into an input field that also triggers a massive UI re-render. In Sync mode, the main thread is blocked. In Concurrent mode, the work is yielded, keeping the input fast.
Interactive Diagram: The Main Thread Scheduler
Sync vs Concurrent Rendering
In Synchronous mode, a heavy render is one giant block. The browser cannot handle new typing events, paint frames, or do anything else until it finishes. The app feels broken.
Check yourself
Pick an answer to lock it in, then read why. Getting one wrong is part of how it sticks.
Remember this
- Before React 18, all rendering was synchronous and un-interruptible.
- Concurrent rendering allows React to pause heavy renders to handle urgent user events (like typing).
- Use
startTransitionto mark a state update as non-urgent. - Use
useDeferredValueto defer updating a value passed into a heavy component. - Concurrency is cooperative scheduling on the main thread, not multi-threading.
Done with this concept?
Mark it complete to track your progress. No login needed.