React 18 introduced major upgrades under the hood — especially around concurrent rendering, automatic batching, and new hooks that enhance performance and user experience.
These features make React smarter and more responsive without changing how you write most components.
Before React 18, multiple state updates in async functions caused multiple renders. Now, React batches all updates automatically — even inside timeouts, promises, or event handlers.
// React 18+ automatic batching example
import React, { useState } from "react";
function Counter() {
const [count, setCount] = useState(0);
const [text, setText] = useState("");
const handleClick = () => {
setTimeout(() => {
// ✅ Both updates are batched together (1 re-render)
setCount((c) => c + 1);
setText("Updated!");
}, 1000);
};
return (
<div>
<p>Count: {count}</p>
<p>Text: {text}</p>
<button onClick={handleClick}>Update</button>
</div>
);
}
React intelligently batches these updates into one render, improving performance.
Concurrent rendering makes UI updates interruptible. It allows React to pause, resume, or drop low-priority updates — keeping the UI responsive even during heavy work. This works behind the scenes and powers hooks like useTransition().
The useTransition() hook helps distinguish between urgent and non-urgent updates. React defers the latter to keep the UI responsive.
// Import useTransition for concurrent updates
import React, { useState, useTransition } from "react";
function SearchBox() {
const [query, setQuery] = useState("");
const [results, setResults] = useState([]);
// isPending tells us if a transition is active
const [isPending, startTransition] = useTransition();
const handleChange = (e) => {
setQuery(e.target.value); // Urgent update (input field)
startTransition(() => {
// Simulate slow filter / Non-urgent update
const filtered = Array(5000).fill("Item")
.filter(item => item.includes(e.target.value));
setResults(filtered);
});
};
return (
<div>
<input value={query} onChange={handleChange} />
{isPending ? <p>Loading...</p> : <p>Results: {results.length}</p>}
</div>
);
}
isPending indicates when React is deferring a state update, improving perceived performance.
useDeferredValue() delays rendering of a specific value until higher-priority updates (like typing) complete.
import React, { useState, useDeferredValue } from "react";
function DeferredList({ input }) {
// Defers using the new input value until urgent tasks finish
const deferredInput = useDeferredValue(input);
const list = Array(2000).fill("Item")
.map((_, i) => <li key={i}>{deferredInput} - {i}</li>);
return <ul>{list}</ul>;
}
export default function App() {
const [text, setText] = useState("");
return (
<div>
<input value={text} onChange={(e) => setText(e.target.value)} />
<DeferredList input={text} />
</div>
);
}
This keeps input responsive even when rendering large lists.
React 18 extends Suspense to data fetching, allowing components to "wait" for async data with fallback UI.
import React, { Suspense } from "react";
import Profile from "./Profile";
export default function App() {
return (
// Fallback UI is shown while Profile data loads
<Suspense fallback={<p>Loading profile...</p>}>
<Profile />
</Suspense>
);
}
Combined with data frameworks (like React Query), it enables smoother async UX.
See the difference between how React 17 and React 18 handle 3 consecutive state updates inside an asynchronous function (like setTimeout).
| Feature | Description | Benefit |
|---|---|---|
| Automatic Batching | Combines multiple state updates | Improves performance |
| Concurrent Rendering | Prioritizes important updates | Smoother UX |
| useTransition | Defers low-priority state updates | Prevents UI lag |
| useDeferredValue | Defers rendering of slow components | Maintains interactivity |
| Suspense | Handles async data loading | Cleaner async UI |
useTransition for deferred updates instead of manual throttling.Suspense for better loading UX.useTransition().useDeferredValue() for large data renders.Suspense with a fake API delay to visualize fallback loading.Goal: Master React 18+ features that deliver better performance, smoother UI updates, and modern concurrent capabilities.