React Infinite Scroll Component

7.1.0 · active · verified Sun Apr 19

`react-infinite-scroll-component` is a lightweight (4.15 kB) and efficient React component designed to implement infinite scrolling experiences in web applications. The current stable version is v7.1.0, with an active development cadence indicated by recent major and minor releases. A key differentiator is its transition to an `IntersectionObserver`-based triggering mechanism in v7.1.0, which enhances performance by running off the main thread and eliminating the need for scroll event throttling, leading to zero runtime dependencies. It supports conventional bottom-to-top scrolling, inverse scrolling (top-to-bottom), and a "pull down to refresh" feature. The component can operate on the document body, within a fixed-height container, or target a specific scrollable DOM element via its ID or a direct `HTMLElement` reference, offering flexibility in integration scenarios. It also requires React 17+ and Node.js 18.18.0+ for development.

Common errors

Warnings

Install

Imports

Quickstart

Demonstrates a basic infinite scroll setup with data loading, a loading indicator, an end message, and optional pull-down-to-refresh functionality within a defined scrollable container.

import React, { useState } from 'react';
import InfiniteScroll from 'react-infinite-scroll-component';

interface Item {
  id: number;
  content: string;
}

const style = {
  padding: 15,
  borderBottom: '1px solid #eee',
  minHeight: 50,
};

const App: React.FC = () => {
  const [items, setItems] = useState<Item[]>(
    Array.from({ length: 20 }, (_, i) => ({ id: i, content: `Initial Item #${i}` }))
  );
  const [hasMore, setHasMore] = useState(true);

  const fetchMoreData = () => {
    if (items.length >= 100) {
      setHasMore(false);
      return;
    }
    // Simulate an API call
    setTimeout(() => {
      setItems((prevItems) => [
        ...prevItems,
        ...Array.from({ length: 20 }, (_, i) => ({
          id: prevItems.length + i,
          content: `Fetched Item #${prevItems.length + i}`,
        })),
      ]);
    }, 1500);
  };

  const refreshData = () => {
    // Simulate re-fetching initial data for pull-to-refresh
    return new Promise<void>((resolve) => {
      setTimeout(() => {
        setItems(Array.from({ length: 20 }, (_, i) => ({ id: i, content: `Refreshed Item #${i}` })));
        setHasMore(true);
        resolve();
      }, 1000);
    });
  };

  return (
    <div>
      <h1 style={{ textAlign: 'center' }}>Infinite Scroll Demo</h1>
      <div
        id="scrollableDiv"
        style={{
          height: 400,
          overflow: 'auto',
          margin: '20px auto',
          border: '1px solid #ccc',
          width: '80%',
        }}
      >
        <InfiniteScroll
          dataLength={items.length}
          next={fetchMoreData}
          hasMore={hasMore}
          loader={<h4>Loading...</h4>}
          endMessage={
            <p style={{ textAlign: 'center', padding: '10px' }}>
              <b>Yay! You have seen it all</b>
            </p>
          }
          refreshFunction={refreshData}
          pullDownToRefresh
          pullDownToRefreshThreshold={50}
          pullDownToRefreshContent={
            <h3 style={{ textAlign: 'center', margin: 0, padding: '10px' }}>&#8595; Pull down to refresh</h3>
          }
          releaseToRefreshContent={
            <h3 style={{ textAlign: 'center', margin: 0, padding: '10px' }}>&#8593; Release to refresh</h3>
          }
          scrollableTarget="scrollableDiv"
        >
          {items.map((item) => (
            <div key={item.id} style={style}>
              {item.content}
            </div>
          ))}
        </InfiniteScroll>
      </div>
    </div>
  );
};

export default App;

view raw JSON →