DEV Community

Cover image for Why React Virtualized Matters: Rendering Smart, Not Hard
Sathish
Sathish

Posted on • Originally published at sathishsaravanan.com

Why React Virtualized Matters: Rendering Smart, Not Hard

If you try to render 10,000 DOM nodes at once, your browser will remind you that it's not a supercomputer.

Ever built a list so long that your app crawled to a halt? Enter React Virtualized — a library that renders only what the user sees, not the entire dataset. It's the frontend equivalent of not reading an entire book just to quote a single line.

Why Virtualization Is Necessary

React’s diffing algorithm is efficient, but not magic. Rendering thousands of DOM nodes is still a bottleneck — especially in large tables, infinite scrolls, or chat apps.

Let’s say you have 10,000 items. Even if each render is 1ms, that’s 10 seconds of blocking work. Virtualization helps you render just a slice of that — say, 20 rows — and swap in new content on scroll.

The performance cost isn’t just CPU cycles. It’s:

  • DOM reflow/repaint
  • Increased memory usage
  • Janky scrolling on low-powered devices

All of this affects user experience — especially when users scroll fast.

🚀 What React Virtualized Does (And How)

React Virtualized calculates visible window height and row height to determine which items should be rendered.

visibleRows = Math.ceil(containerHeight / rowHeight);
offset = scrollTop / rowHeight;
startIndex = Math.floor(offset);
endIndex = startIndex + visibleRows;
Enter fullscreen mode Exit fullscreen mode

That’s it — only rows from startIndex to endIndex are in the DOM. The rest? Skipped, but accounted for using top and bottom spacers to maintain scroll height.

This means you can scroll through 100,000 rows, but only ever render 20–30 in the viewport at a time. The illusion of a massive list stays intact, but your browser stays happy.

A Quick Example

import React from 'react';
import { List, AutoSizer } from 'react-virtualized';

const rowRenderer = ({ index, key, style }) => (
  <div key={key} style={style}>
    Row #{index}
  </div>
);

const MyVirtualizedList = () => (
  <div style={{ width: '100%', height: '600px' }}>
    <AutoSizer>
      {({ height, width }) => (
        <List
          width={width}
          height={height}
          rowHeight={40}
          rowCount={10000}
          rowRenderer={rowRenderer}
        />
      )}
    </AutoSizer>
  </div>
);

export default MyVirtualizedList;
Enter fullscreen mode Exit fullscreen mode

Here’s what’s happening:

  • Renders only what's visible: Thanks to react-virtualized, this list shows ~15–20 rows at a time from a 10,000-row dataset.
  • AutoSizer fills the space: It auto-detects the container size and passes dynamic height/width to the List.
  • rowRenderer customizes display: You decide how each row looks, using index to dynamically render content.
  • High performance UI: Smooth scrolling, minimal DOM load — perfect for dashboards, logs, or infinite scroll UIs.

You can even use CellMeasurer for dynamic height rows, though that comes at a trade-off in performance.

When Should You Use It?

React Virtualized is great for:

  • Financial dashboards
  • Log viewers
  • Chat applications
  • CMS tables
  • Admin panels with expandable rows

Avoid it for:

  • Short lists (<100 items)
  • Static or rarely updated UIs

Sometimes, simpler is better. Always measure before you optimize.

How Does It Compare?

Feature React Virtualized React Window
Mature API ✅ Rich ✅ Simpler
Performance ✅ Fast ✅ Faster
Dynamic Height ⚠️ With CellMeasurer
Ecosystem ✅ Established ✅ Growing

Performance Considerations

Virtualized rendering is fast — but here’s how to keep it that way:

  1. Memoize your rowRenderer
const rowRenderer = useCallback(({ index, key, style }) => (
  <div key={key} style={style}>
    Row #{index}
  </div>
), []);
Enter fullscreen mode Exit fullscreen mode
  1. Avoid layout thrashing
    Keep your row height consistent. If dynamic, debounce expensive layout recalculations.

  2. Lift state up
    Avoid re-rendering the entire list on each interaction.

  3. Use React.memo or shouldComponentUpdate --
    Every millisecond counts.

Advanced Tips

  • Use WindowScroller if your list isn’t scrollable on its own (e.g. inside a long page)
  • Combine with InfiniteLoader for server-side paging
  • Wrap heavy row components with PureComponent or React.memo
  • Use scrollToIndex to programmatically jump to a row

These patterns help when you're building custom UIs with deep integration requirements.


Final Thoughts

React Virtualized is one of those tools that you don’t need — until you really need it. It turns long lists from performance-killers into smooth, scrollable components.

If your app lags on scroll, if dev tools show hundreds of DOM nodes, or if you’re paging through massive datasets — it’s time to think virtual.

It's not about clever tricks. It's about being pragmatic: render what matters, skip what doesn’t.

Top comments (0)