Rendering large lists or data tables in React applications can significantly affect performance. When a list contains hundreds or thousands of items, the browser struggles to render all DOM elements simultaneously, resulting in lag, high memory consumption, and poor user experience. Virtualization, or windowing, is a powerful technique that optimizes rendering by only displaying items currently visible in the viewport and reusing DOM elements as the user scrolls.
This post explores virtualization techniques in React, focusing on React Window, one of the most efficient libraries for rendering large lists. You’ll learn why virtualization matters, how React Window works, how to implement it, and when to use it for the best results.
Understanding the Problem of Large Lists
When rendering a large dataset — for example, a list of 10,000 users — React creates and manages thousands of DOM nodes simultaneously. Even though most of those items are not visible on the screen, the browser still needs to process them.
This results in:
- Sluggish scrolling performance.
- Increased memory usage.
- Slow re-rendering when state updates occur.
- Poor overall user experience on low-end devices.
Example of a Non-Virtualized List
function LargeList({ items }) {
return (
<div>
{items.map((item, index) => (
<div key={index} style={{ padding: '10px', borderBottom: '1px solid #ccc' }}>
{item}
</div>
))}
</div>
);
}
This simple list component renders every single item in the array, which can easily freeze your browser if the list is too large.
What Is Virtualization (Windowing)?
Virtualization is the process of rendering only a subset of visible elements while efficiently reusing DOM nodes as the user scrolls.
Instead of displaying all 10,000 list items, only those currently visible in the viewport — say 20 or 30 — are rendered. As the user scrolls, the component dynamically adjusts which items are displayed.
This process drastically reduces the number of DOM nodes, improving performance and responsiveness.
Introducing React Window
React Window is a lightweight library built by Brian Vaughn (the same developer behind React Virtualized). It’s designed to handle rendering large lists and grids efficiently with minimal setup.
It provides two main components:
FixedSizeList
– for lists where each item has a fixed height.VariableSizeList
– for lists where each item’s height can vary.
Installing React Window
You can install React Window using npm or yarn:
npm install react-window
or
yarn add react-window
Once installed, you can start using it to optimize your large list components.
Rendering a Simple Fixed Size List
The simplest use case involves rendering a list where all items have a fixed height.
import { FixedSizeList as List } from 'react-window';
const items = Array.from({ length: 10000 }, (_, index) => Item ${index}
);
function Row({ index, style }) {
return (
<div style={style}>
{items[index]}
</div>
);
}
export default function App() {
return (
<List
height={400}
itemCount={items.length}
itemSize={35}
width={300}
>
{Row}
</List>
);
}
Explanation
height
– the total visible height of the list container.itemCount
– the total number of list items.itemSize
– the fixed height of each item.width
– the list container’s width.- The
style
prop passed intoRow
ensures that each item is positioned correctly within the scrollable area.
React Window handles the complex part of only rendering the items visible within the viewport while reusing DOM nodes for performance.
Styling and Customization
You can easily add styles or even complex components inside each row:
function Row({ index, style }) {
return (
<div style={{ ...style, display: 'flex', justifyContent: 'space-between', padding: '10px', borderBottom: '1px solid #eee' }}>
<span>Item #{index}</span>
<button>View</button>
</div>
);
}
Each item still benefits from virtualization while maintaining a clean layout and structure.
Handling Variable Item Sizes
Sometimes, items in a list don’t all have the same height — for example, chat messages or articles of different lengths. In this case, you can use the VariableSizeList component.
import { VariableSizeList as List } from 'react-window';
const items = Array.from({ length: 1000 }, (_, index) => Item ${index}
);
function getItemSize(index) {
return index % 2 === 0 ? 50 : 100; // alternating heights
}
function Row({ index, style }) {
return (
<div style={style}>
{items[index]}
</div>
);
}
export default function App() {
return (
<List
height={400}
itemCount={items.length}
itemSize={getItemSize}
width={300}
>
{Row}
</List>
);
}
With VariableSizeList
, React Window dynamically adjusts rendering for items of different sizes, maintaining performance efficiency.
Integrating React Window with Dynamic Data
In many applications, data is fetched from an API rather than being static. React Window integrates seamlessly with dynamic data sources.
import { FixedSizeList as List } from 'react-window';
import { useEffect, useState } from 'react';
export default function App() {
const [data, setData] = useState([]);
useEffect(() => {
fetch('https://jsonplaceholder.typicode.com/posts')
.then(res => res.json())
.then(setData);
}, []);
const Row = ({ index, style }) => (
<div style={style}>
{data[index]?.title || 'Loading...'}
</div>
);
return (
<List
height={400}
itemCount={data.length}
itemSize={35}
width={500}
>
{Row}
</List>
);
}
This example demonstrates how you can fetch data asynchronously while still leveraging virtualization to keep rendering efficient.
React Window vs React Virtualized
Before React Window, the most popular library for virtualization was React Virtualized. While both achieve similar goals, they differ in size and complexity.
Feature | React Window | React Virtualized |
---|---|---|
Bundle size | Smaller (~3KB gzipped) | Larger (~35KB gzipped) |
API simplicity | Minimal and straightforward | Complex and feature-rich |
Performance | Faster in most cases | Slightly slower due to feature overhead |
Features | Basic lists and grids | Advanced features like cell measurer and auto sizer |
If you need simple, efficient virtualization for lists or grids, React Window is usually the best choice. For more advanced use cases (like multi-directional scrolling or auto-sizing grids), React Virtualized may still be useful.
Working with Infinite Scrolling
React Window can be easily combined with infinite scrolling to fetch more data as the user scrolls.
Here’s an example that simulates infinite loading:
import { FixedSizeList as List } from 'react-window';
import { useState, useEffect } from 'react';
export default function InfiniteScrollList() {
const [items, setItems] = useState(Array.from({ length: 50 }, (_, i) => Item ${i}
));
const loadMoreItems = () => {
setTimeout(() => {
setItems(prev => [
...prev,
...Array.from({ length: 50 }, (_, i) => Item ${prev.length + i}
)
]);
}, 1000);
};
const Row = ({ index, style }) => {
if (index === items.length - 1) {
loadMoreItems();
}
return <div style={style}>{items[index]}</div>;
};
return (
<List
height={400}
itemCount={items.length}
itemSize={35}
width={300}
>
{Row}
</List>
);
}
This approach lets you render thousands of items without ever overwhelming the browser.
Combining React Window with AutoSizer
In responsive layouts, it’s often necessary for lists to automatically adjust their height or width based on the container. This can be achieved using the react-virtualized-auto-sizer
package.
npm install react-virtualized-auto-sizer
Example:
import { FixedSizeList as List } from 'react-window';
import AutoSizer from 'react-virtualized-auto-sizer';
export default function ResponsiveList({ items }) {
const Row = ({ index, style }) => (
<div style={style}>{items[index]}</div>
);
return (
<AutoSizer>
{({ height, width }) => (
<List
height={height}
width={width}
itemCount={items.length}
itemSize={35}
>
{Row}
</List>
)}
</AutoSizer>
);
}
Now, the list automatically adapts to its parent container size, ensuring responsive design.
Performance Benefits of Virtualization
Using React Window provides significant performance improvements:
- Reduced DOM Nodes: Only visible elements are rendered.
- Improved Scrolling: Smooth performance even with thousands of items.
- Faster Rendering: Less CPU and memory usage.
- Scalability: Handles dynamic or remote data effortlessly.
These benefits make virtualization essential for modern, data-heavy React applications.
Common Use Cases for React Window
React Window is ideal for:
- Large tables or data grids.
- Chat applications with long message lists.
- E-commerce product catalogs.
- News feeds or social media timelines.
- File explorers or logs with extensive entries.
Limitations of React Window
While React Window is powerful, it also has limitations:
- No built-in auto-sizing for dynamic content (requires additional packages).
- Limited built-in support for sticky headers or columns.
- Lacks complex layout utilities that React Virtualized offers.
- Requires careful height calculation for variable-sized lists.
Leave a Reply