Concurrent Rendering is one of the core innovations in React 18+. It allows React to prepare multiple versions of the UI simultaneously — making updates smoother, faster, and more interruptible.
Instead of rendering everything synchronously and blocking the UI, React can now pause, resume, or even cancel rendering tasks based on priority.
In React 17 and earlier, rendering was synchronous. When a heavy component rendered, it blocked the main thread — freezing the UI until completion.
// React 17: Legacy behavior
setState(heavyData); // causes noticeable lag
This could make typing, animations, or other interactions feel sluggish because the browser couldn't process input events until the render finished.
React 18 introduces a concurrent renderer that works asynchronously. It can:
This is made possible through new concurrent APIs like useTransition, useDeferredValue, and startTransition.
Here’s a simple example showing how concurrent rendering keeps the UI responsive while rendering heavy data.
// 1. Import useTransition for concurrency control
import React, { useState, useTransition } from "react";
function SlowList({ text }) {
// Intentionally heavy operation: creating 3000 items
const items = Array(3000).fill(0).map((_, i) => <li key={i}>{text} - Item {i}</li>);
return <ul>{items}</ul>;
}
export default function ConcurrentExample() {
const [input, setInput] = useState("");
const [list, setList] = useState([]);
// 2. Initialize the hook
const [isPending, startTransition] = useTransition();
const handleChange = (e) => {
const value = e.target.value;
// 3. High Priority: Update input immediately so typing feels fast
setInput(value);
// 4. Low Priority: Wrap heavy updates in startTransition
startTransition(() => {
setList(Array(3000).fill(value));
});
};
return (
<div className="p-3">
<input
className="form-control mb-2"
value={input}
onChange={handleChange}
placeholder="Type something..."
/>
// 5. Show loading state if transition is pending
{isPending ? <p>Updating list...</p> : <SlowList text={input} />}
</div>
);
}
This demo simulates how the Browser Main Thread handles heavy work.
Instruction: Click a button below, then immediately try to type in the input box.
| Aspect | React 17 (Synchronous) | React 18 (Concurrent) |
|---|---|---|
| Rendering Model | Blocking, single-threaded | Interruptible, cooperative |
| Performance | Freezes on heavy updates | Smooth, responsive UI |
| Prioritization | No priority distinction | High vs low priority updates |
| Developer APIs | Legacy updates only | useTransition(), startTransition() |
useTransition() for deferred updates (like filters, lists).Suspense for best async UX.useTransition().Suspense and observe how it keeps UI responsive during async fetches.Goal: Understand how concurrent rendering helps React handle heavy or async updates while maintaining a fluid user experience.