React List is a powerful library for rendering large lists efficiently in React applications using virtualization. It only renders the items visible in the viewport, dramatically improving performance for lists with thousands or millions of items. This guide walks through implementing advanced list virtualization using React List with React, covering dynamic item heights, infinite scrolling, and performance optimization patterns. This is part 24 of a series on using React List with React.
Prerequisites
Before you begin, ensure you have:
- Node.js version 16.0 or higher
- npm, yarn, or pnpm package manager
- A React project (version 16.8 or higher) with hooks support
- Advanced understanding of React hooks, refs, and performance optimization
- Familiarity with virtualization concepts
- Knowledge of TypeScript (recommended)
Installation
Install React List using your preferred package manager:
npm install react-list
Or with yarn:
yarn add react-list
Or with pnpm:
pnpm add react-list
Your package.json should include:
{
"dependencies": {
"react-list": "^0.8.13",
"react": "^18.0.0",
"react-dom": "^18.0.0"
}
}
Project Setup
React List requires minimal setup. No additional configuration is needed beyond installation.
First Example / Basic Usage
Let's create a basic virtualized list component. Create src/VirtualizedList.jsx:
// src/VirtualizedList.jsx
import React, { useState } from 'react';
import ReactList from 'react-list';
function VirtualizedList() {
const [items] = useState(() => {
// Generate a large array of items
return Array.from({ length: 10000 }, (_, i) => ({
id: i + 1,
name: `Item ${i + 1}`,
description: `This is item number ${i + 1}`
}));
});
const renderItem = (index, key) => {
const item = items[index];
return (
<div
key={key}
style={{
padding: '16px',
borderBottom: '1px solid #eee',
height: '60px',
display: 'flex',
alignItems: 'center'
}}
>
<div>
<strong>{item.name}</strong>
<div style={{ fontSize: '14px', color: '#666' }}>
{item.description}
</div>
</div>
</div>
);
};
return (
<div style={{ padding: '20px' }}>
<h2>Virtualized List (10,000 items)</h2>
<div style={{ height: '600px', overflow: 'auto', border: '1px solid #ddd' }}>
<ReactList
itemRenderer={renderItem}
length={items.length}
type="uniform"
/>
</div>
</div>
);
}
export default VirtualizedList;
Understanding the Basics
React List uses virtualization to render only visible items:
- ReactList: Main component that handles virtualization
- itemRenderer: Function that renders each item
- length: Total number of items in the list
- type: Rendering type ('uniform', 'variable', 'simple')
Key concepts for advanced usage:
- Virtualization: Only renders visible items, improving performance
- Item Renderer: Function that receives index and key, returns React element
- Types: 'uniform' for fixed heights, 'variable' for dynamic heights, 'simple' for basic lists
- Scroll Container: Must have fixed height and overflow
Here's an example with variable item heights:
// src/VariableHeightList.jsx
import React, { useState } from 'react';
import ReactList from 'react-list';
function VariableHeightList() {
const [items] = useState(() => {
return Array.from({ length: 1000 }, (_, i) => ({
id: i + 1,
title: `Item ${i + 1}`,
content: `Content for item ${i + 1}. `.repeat(Math.floor(Math.random() * 5) + 1)
}));
});
const getItemSize = (index) => {
// Calculate height based on content length
const item = items[index];
const lines = Math.ceil(item.content.length / 50);
return Math.max(60, lines * 20 + 40);
};
const renderItem = (index, key) => {
const item = items[index];
return (
<div
key={key}
style={{
padding: '16px',
borderBottom: '1px solid #eee',
backgroundColor: index % 2 === 0 ? '#f9f9f9' : 'white'
}}
>
<h3 style={{ margin: '0 0 8px 0' }}>{item.title}</h3>
<p style={{ margin: 0, color: '#666' }}>{item.content}</p>
</div>
);
};
return (
<div style={{ padding: '20px' }}>
<h2>Variable Height List</h2>
<div style={{ height: '600px', overflow: 'auto', border: '1px solid #ddd' }}>
<ReactList
itemRenderer={renderItem}
length={items.length}
type="variable"
itemSizeGetter={getItemSize}
/>
</div>
</div>
);
}
export default VariableHeightList;
Practical Example / Building Something Real
Let's build a comprehensive data table with virtualization and infinite scrolling:
// src/VirtualizedDataTable.jsx
import React, { useState, useEffect, useRef, useCallback } from 'react';
import ReactList from 'react-list';
interface DataItem {
id: number;
name: string;
email: string;
department: string;
salary: number;
status: string;
}
function VirtualizedDataTable() {
const [data, setData] = useState<DataItem[]>([]);
const [loading, setLoading] = useState(false);
const [hasMore, setHasMore] = useState(true);
const listRef = useRef<ReactList>(null);
// Generate initial data
useEffect(() => {
const initialData = Array.from({ length: 100 }, (_, i) => ({
id: i + 1,
name: `Employee ${i + 1}`,
email: `employee${i + 1}@example.com`,
department: ['Engineering', 'Marketing', 'Sales', 'HR'][i % 4],
salary: 50000 + Math.random() * 100000,
status: i % 3 === 0 ? 'Active' : 'Inactive'
}));
setData(initialData);
}, []);
const loadMore = useCallback(async () => {
if (loading || !hasMore) return;
setLoading(true);
// Simulate API call
setTimeout(() => {
const newData = Array.from({ length: 50 }, (_, i) => ({
id: data.length + i + 1,
name: `Employee ${data.length + i + 1}`,
email: `employee${data.length + i + 1}@example.com`,
department: ['Engineering', 'Marketing', 'Sales', 'HR'][(data.length + i) % 4],
salary: 50000 + Math.random() * 100000,
status: (data.length + i) % 3 === 0 ? 'Active' : 'Inactive'
}));
setData(prev => [...prev, ...newData]);
setLoading(false);
if (data.length + newData.length >= 1000) {
setHasMore(false);
}
}, 500);
}, [data.length, loading, hasMore]);
const handleScroll = useCallback((e: React.UIEvent<HTMLDivElement>) => {
const target = e.currentTarget;
const scrollBottom = target.scrollHeight - target.scrollTop - target.clientHeight;
if (scrollBottom < 100 && hasMore && !loading) {
loadMore();
}
}, [hasMore, loading, loadMore]);
const renderItem = useCallback((index: number, key: string | number) => {
const item = data[index];
if (!item) return null;
return (
<div
key={key}
style={{
display: 'grid',
gridTemplateColumns: '80px 200px 250px 150px 120px 120px',
padding: '12px',
borderBottom: '1px solid #eee',
backgroundColor: index % 2 === 0 ? '#f9f9f9' : 'white',
alignItems: 'center'
}}
>
<div>{item.id}</div>
<div>
<strong>{item.name}</strong>
<div style={{ fontSize: '12px', color: '#666' }}>{item.email}</div>
</div>
<div>
<span style={{
padding: '4px 8px',
borderRadius: '4px',
backgroundColor: '#007bff',
color: 'white',
fontSize: '12px'
}}>
{item.department}
</span>
</div>
<div>${item.salary.toLocaleString()}</div>
<div>
<span style={{
padding: '4px 8px',
borderRadius: '4px',
backgroundColor: item.status === 'Active' ? '#d4edda' : '#f8d7da',
color: item.status === 'Active' ? '#155724' : '#721c24',
fontSize: '12px',
fontWeight: 'bold'
}}>
{item.status}
</span>
</div>
<div>
<button
onClick={() => console.log('Edit', item)}
style={{
padding: '4px 8px',
marginRight: '4px',
border: '1px solid #007bff',
backgroundColor: 'white',
color: '#007bff',
borderRadius: '4px',
cursor: 'pointer'
}}
>
Edit
</button>
</div>
</div>
);
}, [data]);
const renderHeader = () => (
<div
style={{
display: 'grid',
gridTemplateColumns: '80px 200px 250px 150px 120px 120px',
padding: '12px',
backgroundColor: '#f5f5f5',
borderBottom: '2px solid #ddd',
fontWeight: 'bold',
position: 'sticky',
top: 0,
zIndex: 1
}}
>
<div>ID</div>
<div>Name</div>
<div>Department</div>
<div>Salary</div>
<div>Status</div>
<div>Actions</div>
</div>
);
return (
<div style={{ padding: '20px' }}>
<h2>Virtualized Data Table</h2>
<div style={{ marginBottom: '8px', color: '#666' }}>
Showing {data.length} items {hasMore ? '(scroll to load more)' : '(all loaded)'}
</div>
<div
style={{
height: '600px',
overflow: 'auto',
border: '1px solid #ddd',
borderRadius: '4px'
}}
onScroll={handleScroll}
>
{renderHeader()}
<ReactList
ref={listRef}
itemRenderer={renderItem}
length={data.length}
type="uniform"
minSize={60}
/>
{loading && (
<div style={{ padding: '20px', textAlign: 'center' }}>
Loading more items...
</div>
)}
{!hasMore && (
<div style={{ padding: '20px', textAlign: 'center', color: '#666' }}>
No more items to load
</div>
)}
</div>
</div>
);
}
export default VirtualizedDataTable;
This advanced example demonstrates:
- Virtualized list rendering for large datasets
- Infinite scrolling with load more functionality
- Variable item rendering with custom layouts
- Sticky header for table-like structure
- Loading states and end-of-list indicators
- Performance optimization for thousands of items
- Grid layout for table-like appearance
Common Issues / Troubleshooting
List not rendering: Ensure the container has a fixed height and
overflow: autooroverflow: scroll. React List requires a scrollable container.Items not displaying correctly: Verify that
itemRendererfunction returns a valid React element with the providedkey. The function should accept(index, key)parameters.Performance issues: Use
type="uniform"for fixed-height items when possible, as it's more performant thantype="variable". For variable heights, ensureitemSizeGetteris optimized.Scroll position lost: React List maintains scroll position, but if you're updating data, ensure you're not recreating the entire data array on every render. Use stable references.
Variable height calculation: For
type="variable", theitemSizeGetterfunction must return accurate heights. Incorrect heights can cause rendering issues.
Next Steps
Now that you've mastered React List:
- Explore advanced features like horizontal scrolling and grid layouts
- Implement custom scroll behaviors and animations
- Add item selection and interaction handling
- Learn about other virtualization libraries (react-window, react-virtualized)
- Optimize for different screen sizes and orientations
- Add accessibility features
- Check the official repository: https://github.com/orgsync/react-list
- Look for part 25 of this series for more advanced topics
Summary
You've learned how to implement advanced list virtualization with React List to handle large datasets efficiently. The library provides excellent performance for rendering thousands of items by only rendering what's visible, making it perfect for building data-intensive applications.
SEO Keywords
react-list
React list virtualization
react-list tutorial
React virtualized list
react-list installation
React performance optimization
react-list example
React infinite scroll
react-list setup
React large list rendering
react-list variable height
React scroll performance
react-list advanced
React list component
react-list getting started
Top comments (0)