React Infinite Scroll Component
`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
-
npm ERR! ERESOLVE unable to resolve dependency tree
cause Attempting to install `react-infinite-scroll-component` versions older than 7.0.1 with React 18 or 19 due to strict peer dependency requirements.fixUpgrade `react-infinite-scroll-component` to version `^7.0.1` or newer. For example: `npm install react-infinite-scroll-component@latest`. -
ReferenceError: React is not defined
cause This error occurs in React 17+ projects that still include `import React from 'react';` at the top of JSX files, or when using `react-infinite-scroll-component@<7.0.0` with React 17+ configured for the new JSX transform without explicit `import React`.fixFor `react-infinite-scroll-component@>=7.0.0`, ensure React is version 17+ and your build tool is configured for the new JSX transform (which removes the need for `import React`). If you are below v7, upgrade React and this package. -
The 'next' prop function is not being called, or is called unexpectedly.
cause This usually indicates an issue with `dataLength` not being updated, `hasMore` being `false`, or incorrect `scrollableTarget` configuration (especially with `IntersectionObserver` in v7.1.0+).fixVerify that `dataLength` correctly reflects the current number of items, `hasMore` is `true` when more data is expected, and `scrollableTarget` (if used) correctly points to the scrollable container. Ensure your `next` function actually updates the state that `dataLength` depends on.
Warnings
- breaking Version 7.0.0 introduced a breaking change requiring React 17.0.0 or newer. It also leverages the new JSX transform, meaning 'import React' boilerplate is no longer needed.
- breaking Version 7.0.0 raised the minimum Node.js requirement to 18.18.0.
- breaking Starting with v7.1.0, the core scroll-triggering mechanism changed from a throttled scroll event listener to an `IntersectionObserver`. This improves performance by running off the main thread and removed `throttle-debounce` as a dependency. The `onScroll` callback now receives *every* scroll event without internal throttling, which might alter behavior for code relying on the previously throttled events.
- gotcha The `scrollableTarget` prop now accepts a direct `HTMLElement` reference in addition to a string ID. While an improvement, developers should be aware of this expanded type signature for consistency.
- gotcha Prior to v7.0.1, installing the package with React 18 or 19 could lead to peer dependency resolution errors (`ERESOLVE`) due to strict peer dependency declarations.
- gotcha The `dataLength` prop is crucial for correct functionality. It must represent the current total number of items rendered in the scrollable list. If it's not updated correctly as new items are loaded, the `next` function may not be triggered.
Install
-
npm install react-infinite-scroll-component -
yarn add react-infinite-scroll-component -
pnpm add react-infinite-scroll-component
Imports
- InfiniteScroll
import { InfiniteScroll } from 'react-infinite-scroll-component';import InfiniteScroll from 'react-infinite-scroll-component';
- InfiniteScroll
const { InfiniteScroll } = require('react-infinite-scroll-component');const InfiniteScroll = require('react-infinite-scroll-component'); - InfiniteScrollProps
import { InfiniteScrollProps } from 'react-infinite-scroll-component';import type { InfiniteScrollProps } from 'react-infinite-scroll-component';
Quickstart
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' }}>↓ Pull down to refresh</h3>
}
releaseToRefreshContent={
<h3 style={{ textAlign: 'center', margin: 0, padding: '10px' }}>↑ Release to refresh</h3>
}
scrollableTarget="scrollableDiv"
>
{items.map((item) => (
<div key={item.id} style={style}>
{item.content}
</div>
))}
</InfiniteScroll>
</div>
</div>
);
};
export default App;