javascript 37 lines · 8 steps

How a virtualized list works in React

Render only the rows currently on screen so a huge list stays fast to scroll.

Explained by highlit
1import { useRef, useState, useCallback, useMemo } from 'react';
2 
3export function VirtualList({ items, rowHeight = 40, height = 600, overscan = 5, renderRow }) {
4 const [scrollTop, setScrollTop] = useState(0);
5 const containerRef = useRef(null);
6 
7 const handleScroll = useCallback((e) => {
8 setScrollTop(e.currentTarget.scrollTop);
9 }, []);
10 
11 const { startIndex, endIndex, offsetY } = useMemo(() => {
12 const visibleCount = Math.ceil(height / rowHeight);
13 const start = Math.max(0, Math.floor(scrollTop / rowHeight) - overscan);
14 const end = Math.min(items.length, start + visibleCount + overscan * 2);
15 return { startIndex: start, endIndex: end, offsetY: start * rowHeight };
16 }, [scrollTop, height, rowHeight, overscan, items.length]);
17 
18 const visibleItems = items.slice(startIndex, endIndex);
19 
20 return (
21 <div
22 ref={containerRef}
23 onScroll={handleScroll}
24 style={{ height, overflowY: 'auto', position: 'relative' }}
25 >
26 <div style={{ height: items.length * rowHeight }}>
27 <div style={{ transform: `translateY(${offsetY}px)` }}>
28 {visibleItems.map((item, i) => (
29 <div key={startIndex + i} style={{ height: rowHeight }}>
30 {renderRow(item, startIndex + i)}
31 </div>
32 ))}
33 </div>
34 </div>
35 </div>
36 );
37}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Rendering only the visible slice keeps DOM size constant no matter how many items exist.
  2. 2A full-height spacer preserves the real scrollbar while a translate offset positions the rendered window.
  3. 3Overscan renders a few extra rows beyond the viewport to hide blank flashes during fast scrolling.

Related explainers

Share this explainer

Here's the card — post it anywhere.

How a virtualized list works in React — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code