Virtualization (or windowing) is a technique to efficiently render large lists by only displaying the items currently visible in the viewport. React Window is a popular library for implementing virtualization in React applications.
Why Use Virtualization?
- Performance: Renders only visible items instead of the entire list
- Memory Efficiency: Reduces DOM node count
- Smooth Scrolling: Maintains performance with large datasets
- Better UX: Prevents jank and lag with long lists
React Window Basics
Installation
npm install react-window
# or
yarn add react-window
Core Components
- FixedSizeList: For lists with items of the same size
- VariableSizeList: For lists with items of varying sizes
- FixedSizeGrid: For 2D grids with fixed cell sizes
- VariableSizeGrid: For 2D grids with variable cell sizes
Basic Example (FixedSizeList)
import { FixedSizeList as List } from 'react-window';
const Row = ({ index, style }) => (
<div style={style}>
Row {index}
</div>
);
const Example = () => (
<List
height={500}
itemCount={1000}
itemSize={35}
width={300}
>
{Row}
</List>
);
Variable Size List
import { VariableSizeList as List } from 'react-window';
const rowHeights = new Array(1000)
.fill(true)
.map(() => 25 + Math.round(Math.random() * 50));
const Row = ({ index, style }) => (
<div style={style}>
Row {index} (height: {rowHeights[index]}px)
</div>
);
const Example = () => (
<List
height={500}
itemCount={1000}
itemSize={index => rowHeights[index]}
width={300}
>
{Row}
</List>
);
Dynamic Content Loading
Combine with lazy loading for large datasets:
import { FixedSizeList as List } from 'react-window';
const Row = ({ index, style, data }) => (
<div style={style}>
{data[index].name}
</div>
);
const Example = ({ items }) => (
<List
height={500}
itemCount={items.length}
itemSize={35}
width={300}
itemData={items}
>
{Row}
</List>
);
Grid Example
import { FixedSizeGrid as Grid } from 'react-window';
const Cell = ({ columnIndex, rowIndex, style }) => (
<div style={style}>
Item {rowIndex},{columnIndex}
</div>
);
const Example = () => (
<Grid
columnCount={1000}
columnWidth={100}
height={500}
rowCount={1000}
rowHeight={35}
width={800}
>
{Cell}
</Grid>
);
Performance Tips
- Memoize row components: Prevent unnecessary re-renders
- Use CSS transforms: For smoother animations
- Avoid inline styles: Extract to CSS classes when possible
- Implement shouldComponentUpdate: For complex row components
const Row = React.memo(({ index, style, data }) => {
// Your row implementation
});
Advanced Techniques
Infinite Loading
Combine with libraries like react-window-infinite-loader
:
import InfiniteLoader from 'react-window-infinite-loader';
import { FixedSizeList as List } from 'react-window';
const Example = ({ hasNextPage, items, loadMore }) => {
const itemCount = hasNextPage ? items.length + 1 : items.length;
const loadMoreItems = isNextPageLoading ? () => {} : loadMore;
const isItemLoaded = index => !hasNextPage || index < items.length;
const Row = ({ index, style }) => {
if (!isItemLoaded(index)) {
return <div style={style}>Loading...</div>;
}
return <div style={style}>{items[index]}</div>;
};
return (
<InfiniteLoader
isItemLoaded={isItemLoaded}
itemCount={itemCount}
loadMoreItems={loadMoreItems}
>
{({ onItemsRendered, ref }) => (
<List
height={500}
itemCount={itemCount}
itemSize={35}
onItemsRendered={onItemsRendered}
ref={ref}
width={300}
>
{Row}
</List>
)}
</InfiniteLoader>
);
};
Custom Scrollbars
Use react-window
with libraries like react-custom-scrollbars
:
import { List } from 'react-window';
import { Scrollbars } from 'react-custom-scrollbars';
const CustomScrollbars = ({ onScroll, forwardedRef, style, children }) => {
const refSetter = React.useCallback(scrollbarsRef => {
if (scrollbarsRef) {
forwardedRef(scrollbarsRef.view);
} else {
forwardedRef(null);
}
}, [forwardedRef]);
return (
<Scrollbars
ref={refSetter}
style={{ ...style, overflow: 'hidden' }}
onScroll={onScroll}
>
{children}
</Scrollbars>
);
};
const CustomScrollbarsVirtualList = React.forwardRef((props, ref) => (
<CustomScrollbars {...props} forwardedRef={ref} />
));
const Example = () => (
<List
height={500}
itemCount={1000}
itemSize={35}
width={300}
outerElementType={CustomScrollbarsVirtualList}
>
{Row}
</List>
);
When to Use React Window
- Lists with 100+ items
- Grids with large numbers of cells
- Data tables with many rows
- Any scrollable content that might impact performance
React Window is more lightweight than its predecessor (React Virtualized) and is typically the better choice for new projects.