Virtualizing Long Lists with react-window

Loading

When dealing with large datasets in React, rendering every item in a list can significantly degrade the performance of your application. As the number of items increases, the time it takes to render them can cause slowdowns, especially in browsers with limited resources. This is where list virtualization comes in.

Virtualization is a technique that only renders the visible portion of a large list or grid, along with a small buffer, improving performance by reducing the number of DOM nodes that need to be rendered at any given time.

One of the popular libraries to achieve this in React is react-window. It allows for efficient rendering of long lists by only rendering the items that are currently in the viewport and a few extra ones (for smooth scrolling).

How react-window Works

react-window helps with the virtualization of lists by only rendering the items that are in the viewport and some additional items to allow for smooth scrolling. It uses the concept of “windowing” to ensure that only a small subset of items is rendered at any given time.

This significantly reduces the memory usage and speeds up rendering, as it avoids rendering the entire list at once.

Installation

To get started, first install react-window:

npm install react-window

Or with yarn:

yarn add react-window

Using react-window for Virtualizing Lists

Here’s an example of how to use react-window to efficiently render a long list:

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

const longList = Array.from({ length: 1000 }, (_, index) => `Item ${index + 1}`);

const VirtualizedList = () => {
  return (
    <List
      height={400} // Height of the container
      itemCount={longList.length} // Total number of items in the list
      itemSize={35} // Height of each item in the list
      width={300} // Width of the container
    >
      {({ index, style }) => (
        <div style={style}>{longList[index]}</div>
      )}
    </List>
  );
};

export default VirtualizedList;

Explanation of Key Props

  1. height: This is the height of the container where the list will be rendered. It’s important for determining how many items should be rendered at once based on the available height.
  2. itemCount: The total number of items in the list. This is essential for react-window to know the size of the entire list.
  3. itemSize: The height (or width, for horizontal lists) of each item. This allows react-window to calculate how many items will fit within the container.
  4. width: This specifies the width of the container. It’s necessary for determining the layout of each item.
  5. style: react-window provides an inline style object that must be applied to each item. This helps react-window to properly position the items.

Performance Benefits

By using react-window, only the visible items and a few additional ones are rendered, which can result in a huge performance improvement when dealing with large lists. The key benefits include:

  • Memory Efficiency: Only a small number of DOM nodes are rendered.
  • Faster Rendering: Only visible items are rendered, reducing the time spent on rendering non-visible elements.
  • Smooth Scrolling: React-window ensures smooth scrolling by dynamically loading and unloading items as the user scrolls.

Handling Dynamic Item Sizes

If your list items have varying heights, react-window provides the VariableSizeList component to handle such cases. Instead of a fixed height for every item, the height of each item can be calculated dynamically.

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

const longList = Array.from({ length: 1000 }, (_, index) => ({
  text: `Item ${index + 1}`,
  height: Math.floor(Math.random() * 50) + 30, // Random heights between 30px and 80px
}));

const getItemSize = index => longList[index].height;

const VirtualizedVariableSizeList = () => {
  return (
    <List
      height={400}
      itemCount={longList.length}
      itemSize={getItemSize} // Dynamically calculate item size
      width={300}
    >
      {({ index, style }) => (
        <div style={style}>{longList[index].text}</div>
      )}
    </List>
  );
};

export default VirtualizedVariableSizeList;

Handling Infinite Scrolling

react-window can also be used for infinite scrolling, where additional items are loaded as the user scrolls down. This can be achieved by monitoring the scroll position and loading more items when the user reaches the bottom.

Here’s an example of implementing infinite scrolling with react-window:

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

const fetchMoreItems = (startIndex, stopIndex) => {
  return new Array(stopIndex - startIndex + 1).fill(null).map((_, index) => `Item ${startIndex + index + 1}`);
};

const InfiniteScrollList = () => {
  const [items, setItems] = useState(fetchMoreItems(0, 30));

  const loadMoreItems = ({ overscanStopIndex }) => {
    const newItems = fetchMoreItems(items.length, overscanStopIndex);
    setItems(prevItems => [...prevItems, ...newItems]);
  };

  return (
    <List
      height={400}
      itemCount={items.length}
      itemSize={35}
      width={300}
      onItemsRendered={({ visibleStopIndex, overscanStopIndex }) => {
        if (visibleStopIndex === items.length - 1) {
          loadMoreItems({ overscanStopIndex });
        }
      }}
    >
      {({ index, style }) => <div style={style}>{items[index]}</div>}
    </List>
  );
};

export default InfiniteScrollList;

Explanation:

  • fetchMoreItems: This function simulates loading more items. In a real-world scenario, this would fetch data from an API or a database.
  • onItemsRendered: The onItemsRendered callback is triggered whenever the items are rendered. It gives information on which items are visible, and we can use this to check if we need to load more items.

Other Features of react-window

  • Horizontal Lists: You can also create horizontal lists by switching the layout from vertical to horizontal using the horizontal prop.
  • Custom Item Rendering: You can customize the rendering of each item by passing your custom render functions.
  • Dynamic Updates: You can update the list dynamically when new data is available.

Leave a Reply

Your email address will not be published. Required fields are marked *