What are the best practices for rendering large lists in React.js?

Yobi Bina Setiawan
28 Jan 2025 ยท Frontend

Rendering large lists in React efficiently is crucial for maintaining performance and ensuring a smooth user experience. Here are some best practices and techniques to achieve this:

1. Virtualization (Windowing)

  • What it is: Instead of rendering all items in the list at once, only render the items that are visible on the screen. As the user scrolls, dynamically render new items and remove off-screen items.

  • Libraries: Use libraries like react-window or react-virtualized.

2. Pagination

  • What it is: Load and display a subset of the list at a time. When the user requests more items (e.g., by clicking a "Load More" button), fetch and render the next subset.

  • When to use: When the list is too large to render all at once, but virtualization is not necessary.

3. Memoization

  • What it is: Use React.memo to prevent unnecessary re-renders of list items when the parent component re-renders.

  • When to use: When list items are expensive to render and don't change often.

4. Key Prop

  • What it is: Always use a unique key prop for each list item to help React identify which items have changed, been added, or been removed.

  • When to use: Always when rendering lists.

5. Lazy Loading

  • What it is: Load list items asynchronously as they come into view.

  • When to use: When the list data is fetched from an API and you want to load data on demand.

Example: Using react-window for Virtualization

jsx
import React from 'react';
import { FixedSizeList as List } from 'react-window';

const LargeList = ({ data }) => {
  const Row = ({ index, style }) => (
    <div style={style}>
      {/* Render your list item here */}
      {data[index]}
    </div>
  );

  return (
    <List
      height={500} // Height of the visible list
      itemCount={data.length} // Total number of items
      itemSize={50} // Height of each item
      width={300} // Width of the list
    >
      {Row}
    </List>
  );
};

export default LargeList;

Example: Pagination

jsx
import React, { useState } from 'react';

const PaginatedList = ({ data, itemsPerPage }) => {
  const [currentPage, setCurrentPage] = useState(1);

  const indexOfLastItem = currentPage * itemsPerPage;
  const indexOfFirstItem = indexOfLastItem - itemsPerPage;
  const currentItems = data.slice(indexOfFirstItem, indexOfLastItem);

  const paginate = (pageNumber) => setCurrentPage(pageNumber);

  return (
    <div>
      <ul>
        {currentItems.map((item, index) => (
          <li key={index}>{item}</li>
        ))}
      </ul>
      <div>
        {Array.from({ length: Math.ceil(data.length / itemsPerPage) }, (_, i) => (
          <button key={i + 1} onClick={() => paginate(i + 1)}>
            {i + 1}
          </button>
        ))}
      </div>
    </div>
  );
};

export default PaginatedList;

Example: Memoization with React.memo

jsx
import React, { memo } from 'react';

const ListItem = memo(({ item }) => {
  return <div>{item}</div>;
});

const LargeList = ({ data }) => {
  return (
    <ul>
      {data.map((item, index) => (
        <ListItem key={index} item={item} />
      ))}
    </ul>
  );
};

export default LargeList;

Example: Lazy Loading with Intersection Observer

jsx
import React, { useState, useEffect, useRef } from 'react';

const LazyLoadList = ({ data }) => {
  const [visibleItems, setVisibleItems] = useState(data.slice(0, 20));
  const loaderRef = useRef(null);

  useEffect(() => {
    const observer = new IntersectionObserver(
      (entries) => {
        if (entries[0].isIntersecting) {
          setVisibleItems((prev) => [
            ...prev,
            ...data.slice(prev.length, prev.length + 20),
          ]);
        }
      },
      { threshold: 1.0 }
    );

    if (loaderRef.current) {
      observer.observe(loaderRef.current);
    }

    return () => {
      if (loaderRef.current) {
        observer.unobserve(loaderRef.current);
      }
    };
  }, [data]);

  return (
    <div>
      <ul>
        {visibleItems.map((item, index) => (
          <li key={index}>{item}</li>
        ))}
      </ul>
      <div ref={loaderRef}>Loading more...</div>
    </div>
  );
};

export default

Keep Healthy and Happy Coding! ๐Ÿ˜‰