Virtualized List Component
Render large lists efficiently by only rendering visible items with calculated scroll positioning.
import { useState, useRef, useCallback } from 'react';
interface VirtualizedListProps<T> {
items: T[];
itemHeight: number;
containerHeight: number;
renderItem: (item: T, index: number) => React.ReactNode;
}
export function VirtualizedList<T>({
items,
itemHeight,
containerHeight,
renderItem,
}: VirtualizedListProps<T>) {
const [scrollTop, setScrollTop] = useState(0);
const containerRef = useRef<HTMLDivElement>(null);
const startIndex = Math.floor(scrollTop / itemHeight);
const visibleCount = Math.ceil(containerHeight / itemHeight) + 1;
const endIndex = Math.min(startIndex + visibleCount, items.length);
const totalHeight = items.length * itemHeight;
const offsetY = startIndex * itemHeight;
const onScroll = useCallback(() => {
if (containerRef.current) setScrollTop(containerRef.current.scrollTop);
}, []);
return (
<div
ref={containerRef}
onScroll={onScroll}
style={{ height: containerHeight, overflow: 'auto' }}
>
<div style={{ height: totalHeight, position: 'relative' }}>
<div style={{ transform: `translateY(${offsetY}px)` }}>
{items.slice(startIndex, endIndex).map((item, i) =>
renderItem(item, startIndex + i)
)}
</div>
</div>
</div>
);
}Use Cases
- Rendering 10k+ item lists
- Log viewers
- Data tables
Tags
Related Snippets
Similar patterns you can reuse in the same workflow.
useDebounce — Debounced Value Hook
Debounce any rapidly-changing value with a configurable delay. Useful for search inputs and resize handlers.
Infinite Scroll with Intersection Observer
Load more items as the user scrolls using IntersectionObserver. No external libraries required.
useIntersectionObserver Hook
Track element visibility with the Intersection Observer API for lazy loading and scroll animations.
Drag & Drop Sortable List
Reorder list items with native HTML drag and drop events — no external library required.