When building React applications that deal with large lists, rendering every item at once can lead to poor performance, sluggish UI, and high memory consumption. This is where the windowing technique comes in.
Windowing is a performance optimization technique that only renders a subset of items visible in the viewport and a small buffer (the “window”)—rather than rendering the entire list at once.
In this article, we’ll explore what windowing is, how it works, and how to implement it efficiently in React using tools like react-window.
The Problem: Rendering Long Lists in React
Let’s say you’re building a UI to show 10,000 items:
const LongList = ({ items }) => {
return (
<div>
{items.map(item => (
<div key={item.id}>{item.text}</div>
))}
</div>
);
};
While this code works, rendering thousands of DOM elements can:
- Slow down initial page load
- Cause noticeable lag during scroll
- Drain memory and CPU, especially on low-end devices
The Solution: Windowing
Windowing (also called virtualization) solves this by:
- Only rendering items currently in the viewport
- Skipping rendering of off-screen elements
- Improving performance without affecting UX
Think of it like a window into your data:
- If you’re scrolling a list of 10,000 items,
- But only 10 are visible at a time,
- The component will render just 10–20 items (a few more for smooth scrolling)
Tools for Windowing in React
React doesn’t have built-in support for windowing, but open-source libraries make it easy.
Popular libraries:
react-window– Lightweight and fast.react-virtualized– More features, larger bundle size.virtuoso– Highly customizable, good for complex use cases.
We’ll use react-window for demonstration—it’s simple and efficient.
Basic Example with react-window
Step 1: Install it
npm install react-window
Step 2: Use FixedSizeList to render a virtualized list
import { FixedSizeList as List } from 'react-window';
const items = Array.from({ length: 10000 }, (_, index) => `Item ${index}`);
const Row = ({ index, style }) => (
<div style={style}>
{items[index]}
</div>
);
const VirtualizedList = () => (
<List
height={400} // total height of the container
itemCount={items.length} // total number of items
itemSize={35} // height of each item
width={300} // width of the container
>
{Row}
</List>
);
- Only a few rows are mounted in the DOM at any time
- DOM stays light, scrolling stays smooth—even with 100,000+ items
How Does It Work Internally?
Windowing libraries calculate:
- Which items are in the visible range
- Which items should be rendered just before and after the visible range (buffering)
- Scroll position to dynamically load and unload items as needed
This keeps the number of rendered DOM nodes minimal, no matter how many items you have.
When to Use Windowing?
Use it when:
- You’re rendering hundreds or thousands of items
- The list is scrollable or paginated
- You want snappy UX with minimal re-renders
Examples:
- Chat apps (long message history)
- Financial dashboards (stock tickers)
- Admin panels with big data tables
Caveats and Gotchas
- Dynamic row heights are trickier — you’ll need
VariableSizeList. - Items outside the viewport aren’t mounted, so effects (like
useEffect) won’t run for them until they’re visible. - Avoid depending on DOM elements that aren’t rendered yet.
