Skip to content

useVirtualList

A React hook that efficiently renders only a subset of a large list based on scroll position, dramatically improving performance for long lists.

Overview

useVirtualList implements windowing for large lists by calculating which items are visible in the viewport and only rendering those. This reduces DOM node count and memory usage, resulting in smoother scrolling and faster rendering, especially for lists with thousands of items.

Import

tsx
import { useVirtualList } from "react-performify";

Example

tsx
import React, { useRef, useState } from "react";
import { useVirtualList } from "react-performify";

function VirtualList({ items }) {
  const containerRef = useRef(null);
  const [scrollTop, setScrollTop] = useState(0);

  const { visibleItems, startOffset } = useVirtualList(items, {
    itemHeight: 40,
    height: 400,
    scrollTop,
  });

  return (
    <div
      ref={containerRef}
      style={{ height: 400, overflowY: "auto", position: "relative" }}
      onScroll={e => setScrollTop(e.target.scrollTop)}
    >
      <div style={{ height: items.length * 40, position: "relative" }}>
        <div style={{ position: "absolute", top: startOffset }}>
          {visibleItems.map((item, idx) => (
            <div key={startOffset + idx} style={{ height: 40 }}>
              {item}
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}

// Usage
function App() {
  const items = Array.from({ length: 1000 }, (_, i) => `Item ${i + 1}`);
  return <VirtualList items={items} />;
}

API Reference

ParameterTypeDescription
itemsarrayThe full list of items.
optionsobject{ itemHeight: number, height: number, scrollTop: number }

Returns: { visibleItems: T[], startOffset: number }

Implementation

tsx
import { useMemo } from "react";

export function useVirtualList<T>(
    items: T[],
    options: { itemHeight: number; height: number; scrollTop: number }
) {
    const { itemHeight, height, scrollTop } = options;

    return useMemo(() => {
        const start = Math.floor(scrollTop / itemHeight);
        const end = Math.min(
            items.length - 1,
            Math.floor((scrollTop + height) / itemHeight)
        );
        const visibleItems = items.slice(start, end + 1);
        const startOffset = start * itemHeight;
        return { visibleItems, startOffset };
    }, [items, itemHeight, height, scrollTop]);
}

Notes

  • Only the visible portion of the list is rendered.
  • Great for chat apps, feeds, or any large dataset.
  • Works with fixed item heights.

Type Definition

tsx
function useVirtualList<T>(
    items: T[],
    options: { itemHeight: number; height: number; scrollTop: number }
): { visibleItems: T[]; startOffset: number }

Summary

Efficiently render large lists by windowing visible items, reducing memory and improving scroll performance in React.