typescriptadvanced
React Virtual List Component
Render large lists efficiently with windowing to only mount visible items in the viewport.
typescriptPress ⌘/Ctrl + Shift + C to copy
'use client';
import { useState, useRef, useCallback, useEffect } from 'react';
interface VirtualListProps<T> {
items: T[];
itemHeight: number;
containerHeight: number;
overscan?: number;
renderItem: (item: T, index: number) => React.ReactNode;
}
export function VirtualList<T>({
items,
itemHeight,
containerHeight,
overscan = 5,
renderItem,
}: VirtualListProps<T>) {
const [scrollTop, setScrollTop] = useState(0);
const containerRef = useRef<HTMLDivElement>(null);
const totalHeight = items.length * itemHeight;
const startIndex = Math.max(0, Math.floor(scrollTop / itemHeight) - overscan);
const endIndex = Math.min(
items.length,
Math.ceil((scrollTop + containerHeight) / itemHeight) + overscan
);
const visibleItems = items.slice(startIndex, endIndex);
const onScroll = useCallback((e: React.UIEvent<HTMLDivElement>) => {
setScrollTop(e.currentTarget.scrollTop);
}, []);
return (
<div
ref={containerRef}
onScroll={onScroll}
style={{ height: containerHeight, overflow: 'auto' }}
>
<div style={{ height: totalHeight, position: 'relative' }}>
{visibleItems.map((item, i) => (
<div
key={startIndex + i}
style={{
position: 'absolute',
top: (startIndex + i) * itemHeight,
height: itemHeight,
width: '100%',
}}
>
{renderItem(item, startIndex + i)}
</div>
))}
</div>
</div>
);
}
// Usage
interface LogEntry { id: number; message: string; level: string }
function LogViewer({ logs }: { logs: LogEntry[] }) {
return (
<VirtualList
items={logs}
itemHeight={40}
containerHeight={600}
renderItem={(log, index) => (
<div className="flex items-center px-4 border-b border-white/5">
<span className="text-gray-500 w-12">{index}</span>
<span className={log.level === 'error' ? 'text-red-400' : 'text-gray-300'}>
{log.message}
</span>
</div>
)}
/>
);
}Use Cases
- Rendering thousands of list items efficiently
- Log viewers and data tables without lag
- Infinite scroll with constant DOM node count
Tags
Related Snippets
Similar patterns you can reuse in the same workflow.
typescriptadvanced
Virtualized List Component
Render large lists efficiently by only rendering visible items with calculated scroll positioning.
Best for: Rendering 10k+ item lists
#virtualization#performance
typescriptintermediate
React Intersection Observer Hook
Custom useIntersectionObserver hook for lazy loading, infinite scroll, and scroll animations.
Best for: Lazy loading components when they enter viewport
#react#hooks
typescriptintermediate
useThrottle Hook for Rate Limiting
Throttle rapidly-firing values like scroll or resize events with a configurable delay hook.
Best for: Scroll position tracking
#react#hooks
typescriptadvanced
Context Selector Pattern
Avoid unnecessary re-renders with a context selector pattern that subscribes to specific state slices.
Best for: High-performance global state
#react#context