HomeAbout Me

React Performance: Concurrent Rendering

By Daniel Nguyen
Published in React JS
July 13, 2025
3 min read
React Performance: Concurrent Rendering

šŸš€ Smooth React UIs with Concurrent Rendering and useDeferredValue

When building modern web apps, we often hit a critical UX bottleneck: performance during complex renders. Whether you’re filtering long lists or loading content dynamically, sluggish UIs can frustrate users and break immersion.

React 18 introduced concurrent rendering to help address this. In this post, we’ll explore what concurrent rendering is, how it works, and how you can use tools like useDeferredValue and memo to keep your app responsive—even under load.


🧠 Why Performance Matters: The 16ms Rule

To feel smooth, a web app should update at 60 frames per second. That gives you around 16 milliseconds per frame to complete your JavaScript work—including rendering your React components.

If React spends more than that on rendering, the browser can’t paint the next frame in time, leading to jank, input lag, and stuttering animations.

But what if your app legitimately has too much to do in one frame? Enter concurrent rendering.


āš™ļø What Is Concurrent Rendering?

Concurrent rendering is a new architecture in React 18 that allows React to pause a render that’s taking too long, let the browser catch up, and then resume rendering later—without blocking user interactions.

Imagine React slicing up rendering work into chunks. While rendering, React checks: ā€œAm I taking too long?ā€ If yes, it yields to the browser and picks up where it left off when there’s time.

This way, expensive renders like large lists don’t freeze the UI.

To learn more about the theory behind this, check out:

  • React v18 Release Notes
  • Dan Abramov’s Talk at JSConf Iceland
  • React 18 Keynote

šŸŖ„ But React Can’t Prioritize On Its Own…

React is smart—but it doesn’t know which parts of your UI are high priority. For example, a user typing in an input should feel snappy, while rendering a giant list of filtered results can wait.

You need to tell React what to deprioritize—and that’s where useDeferredValue comes in.


🧪 Introducing useDeferredValue

The useDeferredValue hook lets you flag certain values as less urgent. It tells React: ā€œRender this later if something more important is happening.ā€

Here’s an example from the official React docs:

function App() {
const [text, setText] = useState('');
const deferredText = useDeferredValue(text); // ← deprioritize this
return (
<>
<input value={text} onChange={e => setText(e.target.value)} />
<SlowList text={deferredText} />
</>
);
}
const SlowList = memo(function SlowList({ text }) {
// Simulate slow rendering
let start = performance.now();
while (performance.now() - start < 50) {} // ā±ļø artificial delay
return <div>{text}</div>;
});

āš ļø Important: Use memo

React can only skip re-rendering slow components with stale data if they’re memoized.

If you don’t wrap the component in React.memo, React will have to re-render it anyway—even with stale data—which defeats the purpose of deferring the value.


šŸ› ļø Real-World Example: Slow Card Rendering

Let’s say you’re building a card search interface:

  • Users type into a search input.
  • A grid of <Card /> components filters and re-renders on each keystroke.
  • But rendering each card is slow (maybe it calculates or formats something).

This is the setup for jank—especially if you filter hundreds of items in real-time.

Step 1: Memoize the Card Component

First, wrap your slow Card component with memo:

const Card = memo(function Card({ data }) {
// Simulate heavy render
let start = performance.now();
while (performance.now() - start < 30) {}
return <div>{data.title}</div>;
});

This tells React: ā€œOnly re-render if props actually change.ā€

Step 2: Defer the Filter Query

If you’re filtering the card list using a search query, you can defer that query like this:

function CardGrid({ query, data }) {
const deferredQuery = useDeferredValue(query);
const filteredData = useMemo(
() => data.filter(card => card.title.includes(deferredQuery)),
[deferredQuery, data]
);
return (
<div className="grid">
{filteredData.map(item => (
<Card key={item.id} data={item} />
))}
</div>
);
}

Now, the user can type freely into the search input, and React will pause filtering and card rendering if the browser needs to remain responsive.

Result?

šŸ’” Typing feels instant, even with expensive components!


šŸŽÆ When to Use useDeferredValue

useDeferredValue shines when:

  • You have user interactions (typing, dragging) and want to keep them smooth
  • You’re rendering large lists, grids, or charts
  • You’re dealing with expensive calculations or heavy UI updates

However:

  • If your component isn’t slow—just optimize the code instead.
  • If you’re loading data, consider Suspense and startTransition.

🧪 Check Performance with React DevTools

Use the React DevTools Profiler to verify:

  • Which components re-render when
  • How long each render takes
  • Whether memoization is preventing unnecessary updates

🧠 Final Tips for Concurrent Rendering

TechniqueUse Case
useDeferredValue()Deprioritize rendering of large or slow updates
React.memo()Prevent re-renders when props haven’t changed
useMemo()Avoid recalculating expensive logic unnecessarily
startTransition()Mark updates as low-priority (especially for data fetching)

šŸ”š Wrapping Up

React’s concurrent rendering model gives you more control over prioritizing user experience. With tools like useDeferredValue and memo, you can balance performance and responsiveness—even when your app needs to do heavy lifting.

If your app feels slow when rendering filtered results or lists, it’s time to let React pause, breathe, and catch up. Defer the less important work, and give the user control center stage.


šŸ“š Further Reading



Tags

#ReactPerformance

Share

Previous Article
React Performance: Optimize Context

Table Of Contents

1
🧠 Why Performance Matters: The 16ms Rule
2
āš™ļø What Is Concurrent Rendering?
3
šŸŖ„ But React Can’t Prioritize On Its Own…
4
🧪 Introducing useDeferredValue
5
šŸ› ļø Real-World Example: Slow Card Rendering
6
šŸŽÆ When to Use useDeferredValue
7
🧪 Check Performance with React DevTools
8
🧠 Final Tips for Concurrent Rendering
9
šŸ”š Wrapping Up

Related Posts

React Performance: Windowing
July 17, 2025
2 min
Ā© 2025, All Rights Reserved.
Powered By

Quick Links

About Me

Legal Stuff

Social Media