React / React Lists / Performance & Virtualization
Home /React /React Lists /Performance & Virtualization

Performance & Virtualization

Performance & Virtualization

List virtualization (also called windowing) is a performance technique where only the list items currently visible in the viewport are rendered into the DOM. Items above and below the visible area are not rendered at all. As the user scrolls, items are dynamically rendered and destroyed. This allows lists of thousands of items to render as fast as lists of 20 items.

React.memo: Prevent Unnecessary Re-renders

JSX

import { memo, useCallback } from 'react';

// memo() wraps the component — only re-renders when props change
const CourseItem = memo(function CourseItem({ course, onDelete }) {
  console.log('Rendered:', course.title); // only logs when this item's props change
  return (
    <li>
      {course.title}
      <button onClick={() => onDelete(course.id)}>Delete</button>
    </li>
  );
});

function CourseList({ courses }) {
  const [other, setOther] = useState(0);

  // useCallback ensures onDelete has a stable reference across renders
  const handleDelete = useCallback((id) => {
    /* delete logic */
  }, []); // stable — no dependencies

  return (
    <div>
      <button onClick={() => setOther((n) => n + 1)}>
        Update other state ({other})
      </button>
      {/* CourseItems do NOT re-render when 'other' changes */}
      <ul>
        {courses.map((c) => (
          <CourseItem key={c.id} course={c} onDelete={handleDelete} />
        ))}
      </ul>
    </div>
  );
}

Virtualization with react-window

JSX

// npm install react-window
import { FixedSizeList } from 'react-window';

// Row renderer — receives index and style from react-window
const Row = ({ index, style, data }) => (
  <div style={style} className="list-row">
    {data[index].title}
  </div>
);

function HugeList({ items }) {
  return (
    {/* Renders only the ~10 visible rows at a time,
        even if items has 50,000 entries */}
    <FixedSizeList
      height={600}         // container height in px
      width={800}           // container width in px
      itemCount={items.length}
      itemSize={56}         // row height in px
      itemData={items}       // passed to Row via data prop
    >
      {Row}
    </FixedSizeList>
  );
}

/* Also available: VariableSizeList for rows of different heights
   For grids: FixedSizeGrid, VariableSizeGrid */
List Size Recommended Approach Why
< 100 items Standard .map() No optimization needed
100 – 1,000 items React.memo + useCallback Prevent unnecessary re-renders
> 1,000 items react-window or react-virtual Virtualization — only render visible rows
Infinite scroll react-infinite-scroll-component Load more items as user scrolls