Both entries refer to the same npm package: react-infinite-scroll-component. This is a lightweight React component that enables infinite scrolling by automatically detecting when the user has scrolled near the bottom of a scrollable container and triggering a callback to load more data. It abstracts away manual scroll event handling and provides a declarative API for rendering loading indicators and end-of-list messages.
You're looking at two identical entries for the same npm package: react-infinite-scroll-component. There is no technical difference to compare because both references point to the exact same library. However, this presents an opportunity to clarify what this package actually does, how it works under the hood, and when it’s appropriate (or not) to use it in professional applications.
react-infinite-scroll-component wraps your scrollable content and listens for scroll events. When the user scrolls within a configurable distance from the bottom, it calls a provided next function to fetch more data. It also handles rendering a loading spinner or a “no more data” message.
Here’s a standard usage pattern:
import InfiniteScroll from 'react-infinite-scroll-component';
function MyList({ items, hasMore, loadMore }) {
return (
<div id="scrollableDiv" style={{ height: '400px', overflow: 'auto' }}>
<InfiniteScroll
dataLength={items.length}
next={loadMore}
hasMore={hasMore}
loader={<h4>Loading...</h4>}
scrollableTarget="scrollableDiv"
>
{items.map(item => <div key={item.id}>{item.name}</div>)}
</InfiniteScroll>
</div>
);
}
The component relies on either the window scroll or a specified scrollable target (via scrollableTarget). Internally, it uses window.addEventListener('scroll', ...) or attaches to the target element’s scroll event.
While simple to integrate, this package has architectural constraints that matter in production:
It renders all loaded items in the DOM. As the list grows, performance degrades due to layout thrashing and memory pressure.
// ❌ Problem: 10,000 items = 10,000 DOM nodes
<InfiniteScroll dataLength={hugeList.length} ...>
{hugeList.map(item => <ExpensiveComponent key={item.id} />)}
</InfiniteScroll>
For large datasets, use react-window or react-virtual instead—they only render visible items.
Although not enforced, smooth scroll detection assumes consistent item heights. If your items have dynamic heights (e.g., user-generated content with variable text), the “near bottom” calculation can become inaccurate, causing premature or missed load triggers.
It attaches scroll listeners without built-in throttling or requestAnimationFrame optimization. In high-frequency scroll scenarios, this can cause jank. You’d need to manually debounce your next handler if data fetching is expensive.
This package is well-suited for:
Example: a notification center that loads 20 items at a time, rarely exceeding 200 total.
// ✅ Good fit: small, predictable dataset
<InfiniteScroll
dataLength={notifications.length}
next={fetchMoreNotifications}
hasMore={notifications.length < totalAvailable}
loader={<Spinner />}
>
{notifications.map(n => <NotificationItem key={n.id} data={n} />)}
</InfiniteScroll>
If your app needs more control, consider these instead:
react-intersection-observer + Manual LogicUse an intersection observer on a sentinel element at the list bottom. Gives you full control over loading logic and avoids scroll event pitfalls.
import { useInView } from 'react-intersection-observer';
function ListWithSentinel({ items, loadMore, hasMore }) {
const { ref, inView } = useInView();
useEffect(() => {
if (inView && hasMore) loadMore();
}, [inView, hasMore]);
return (
<div>
{items.map(item => <Item key={item.id} />)}
{hasMore && <div ref={ref}>Loading...</div>}
</div>
);
}
react-virtual for Large ListsCombines virtualization with infinite scroll patterns. Only renders visible rows, even with 100k+ items.
import { useVirtualizer } from '@tanstack/react-virtual';
function VirtualizedInfiniteList({ items, loadMore, hasNextPage }) {
const parentRef = useRef(null);
const virtualizer = useVirtualizer({
count: hasNextPage ? items.length + 1 : items.length,
getScrollElement: () => parentRef.current,
estimateSize: () => 50,
overscan: 5
});
const virtualItems = virtualizer.getVirtualItems();
// Trigger load when last item is visible
useEffect(() => {
const lastItem = virtualItems[virtualItems.length - 1];
if (lastItem && lastItem.index >= items.length - 1 && hasNextPage) {
loadMore();
}
}, [virtualItems, hasNextPage]);
return (
<div ref={parentRef} style={{ height: '400px', overflow: 'auto' }}>
<div style={{ height: virtualizer.getTotalSize() }}>
{virtualItems.map(virtualItem => {
if (virtualItem.index >= items.length) {
return <div key="loader">Loading...</div>;
}
return <Item key={items[virtualItem.index].id} data={items[virtualItem.index]} />;
})}
</div>
</div>
);
}
Since both entries are the same package, the real decision isn’t which to choose—but whether to use it at all.
react-infinite-scroll-component for simple, low-scale infinite scroll with minimal engineering overhead.In professional frontend architecture, favor composability and performance over convenience when the stakes are high. Sometimes, rolling your own scroll detection with IntersectionObserver yields more maintainable and efficient results than relying on a one-size-fits-all component.
Since both entries reference the identical package, there is no selection decision to make between distinct libraries. Use react-infinite-scroll-component if you need a simple, dependency-free solution for basic infinite scroll behavior in React with minimal setup. Avoid it if you require advanced features like virtualization, dynamic item heights, or complex scroll container configurations — in those cases, consider alternatives such as react-window or react-virtual.
Since both entries reference the identical package, there is no selection decision to make between distinct libraries. Use react-infinite-scroll-component if you need a simple, dependency-free solution for basic infinite scroll behavior in React with minimal setup. Avoid it if you require advanced features like virtualization, dynamic item heights, or complex scroll container configurations — in those cases, consider alternatives such as react-window or react-virtual.
A component to make all your infinite scrolling woes go away with just 4.15 kB! Pull Down to Refresh feature
added. An infinite-scroll that actually works and super-simple to integrate!
npm install --save react-infinite-scroll-component
or
yarn add react-infinite-scroll-component
// in code ES6
import InfiniteScroll from 'react-infinite-scroll-component';
// or commonjs
var InfiniteScroll = require('react-infinite-scroll-component');
<InfiniteScroll
dataLength={items.length} //This is important field to render the next data
next={fetchData}
hasMore={true}
loader={<h4>Loading...</h4>}
endMessage={
<p style={{ textAlign: 'center' }}>
<b>Yay! You have seen it all</b>
</p>
}
// below props only if you need pull down functionality
refreshFunction={this.refresh}
pullDownToRefresh
pullDownToRefreshThreshold={50}
pullDownToRefreshContent={
<h3 style={{ textAlign: 'center' }}>↓ Pull down to refresh</h3>
}
releaseToRefreshContent={
<h3 style={{ textAlign: 'center' }}>↑ Release to refresh</h3>
}
>
{items}
</InfiniteScroll>
<div
id="scrollableDiv"
style={{
height: 300,
overflow: 'auto',
display: 'flex',
flexDirection: 'column-reverse',
}}
>
{/*Put the scroll bar always on the bottom*/}
<InfiniteScroll
dataLength={this.state.items.length}
next={this.fetchMoreData}
style={{ display: 'flex', flexDirection: 'column-reverse' }} //To put endMessage and loader to the top.
inverse={true} //
hasMore={true}
loader={<h4>Loading...</h4>}
scrollableTarget="scrollableDiv"
>
{this.state.items.map((_, index) => (
<div style={style} key={index}>
div - #{index}
</div>
))}
</InfiniteScroll>
</div>
The InfiniteScroll component can be used in three ways.
height prop if you want your scrollable content to have a specific height, providing scrollbars for scrolling your content and fetching more data.scrollableTarget prop to reference the DOM element and use it's scrollbars for fetching more data.height or scrollableTarget props, the scroll will happen at document.body like Facebook's timeline scroll.scrollableTarget (a parent element which is scrollable)
| name | type | description |
|---|---|---|
| next | function | a function which must be called after reaching the bottom. It must trigger some sort of action which fetches the next data. The data is passed as children to the InfiniteScroll component and the data should contain previous items too. e.g. Initial data = [1, 2, 3] and then next load of data should be [1, 2, 3, 4, 5, 6]. |
| hasMore | boolean | it tells the InfiniteScroll component on whether to call next function on reaching the bottom and shows an endMessage to the user |
| children | node (list) | the data items which you need to scroll. |
| dataLength | number | set the length of the data.This will unlock the subsequent calls to next. |
| loader | node | you can send a loader component to show while the component waits for the next load of data. e.g. <h3>Loading...</h3> or any fancy loader element |
| scrollThreshold | number | string | A threshold value defining when InfiniteScroll will call next. Default value is 0.8. It means the next will be called when user comes below 80% of the total height. If you pass threshold in pixels (scrollThreshold="200px"), next will be called once you scroll at least (100% - scrollThreshold) pixels down. |
| onScroll | function | a function that will listen to the scroll event on the scrolling container. Note that the scroll event is throttled, so you may not receive as many events as you would expect. |
| endMessage | node | this message is shown to the user when he has seen all the records which means he's at the bottom and hasMore is false |
| className | string | add any custom class you want |
| style | object | any style which you want to override |
| height | number | optional, give only if you want to have a fixed height scrolling content |
| scrollableTarget | node or string | optional, reference to a (parent) DOM element that is already providing overflow scrollbars to the InfiniteScroll component. You should provide the id of the DOM node preferably. |
| hasChildren | bool | children is by default assumed to be of type array and it's length is used to determine if loader needs to be shown or not, if your children is not an array, specify this prop to tell if your items are 0 or more. |
| pullDownToRefresh | bool | to enable Pull Down to Refresh feature |
| pullDownToRefreshContent | node | any JSX that you want to show the user, default={<h3>Pull down to refresh</h3>} |
| releaseToRefreshContent | node | any JSX that you want to show the user, default={<h3>Release to refresh</h3>} |
| pullDownToRefreshThreshold | number | minimum distance the user needs to pull down to trigger the refresh, default=100px , a lower value may be needed to trigger the refresh depending your users browser. |
| refreshFunction | function | this function will be called, it should return the fresh data that you want to show the user |
| initialScrollY | number | set a scroll y position for the component to render with. |
| inverse | bool | set infinite scroll on top |
Thanks goes to these wonderful people (emoji key):
Ankeet Maini 💬 📖 💻 👀 🚧 | Darsh Shah 🚇 |
This project follows the all-contributors specification. Contributions of any kind are welcome!
A component to make all your infinite scrolling woes go away with just 4.15 kB! Pull Down to Refresh feature
added. An infinite-scroll that actually works and super-simple to integrate!
npm install --save react-infinite-scroll-component
or
yarn add react-infinite-scroll-component
// in code ES6
import InfiniteScroll from 'react-infinite-scroll-component';
// or commonjs
var InfiniteScroll = require('react-infinite-scroll-component');
<InfiniteScroll
dataLength={items.length} //This is important field to render the next data
next={fetchData}
hasMore={true}
loader={<h4>Loading...</h4>}
endMessage={
<p style={{ textAlign: 'center' }}>
<b>Yay! You have seen it all</b>
</p>
}
// below props only if you need pull down functionality
refreshFunction={this.refresh}
pullDownToRefresh
pullDownToRefreshThreshold={50}
pullDownToRefreshContent={
<h3 style={{ textAlign: 'center' }}>↓ Pull down to refresh</h3>
}
releaseToRefreshContent={
<h3 style={{ textAlign: 'center' }}>↑ Release to refresh</h3>
}
>
{items}
</InfiniteScroll>
<div
id="scrollableDiv"
style={{
height: 300,
overflow: 'auto',
display: 'flex',
flexDirection: 'column-reverse',
}}
>
{/*Put the scroll bar always on the bottom*/}
<InfiniteScroll
dataLength={this.state.items.length}
next={this.fetchMoreData}
style={{ display: 'flex', flexDirection: 'column-reverse' }} //To put endMessage and loader to the top.
inverse={true} //
hasMore={true}
loader={<h4>Loading...</h4>}
scrollableTarget="scrollableDiv"
>
{this.state.items.map((_, index) => (
<div style={style} key={index}>
div - #{index}
</div>
))}
</InfiniteScroll>
</div>
The InfiniteScroll component can be used in three ways.
height prop if you want your scrollable content to have a specific height, providing scrollbars for scrolling your content and fetching more data.scrollableTarget prop to reference the DOM element and use it's scrollbars for fetching more data.height or scrollableTarget props, the scroll will happen at document.body like Facebook's timeline scroll.scrollableTarget (a parent element which is scrollable)
| name | type | description |
|---|---|---|
| next | function | a function which must be called after reaching the bottom. It must trigger some sort of action which fetches the next data. The data is passed as children to the InfiniteScroll component and the data should contain previous items too. e.g. Initial data = [1, 2, 3] and then next load of data should be [1, 2, 3, 4, 5, 6]. |
| hasMore | boolean | it tells the InfiniteScroll component on whether to call next function on reaching the bottom and shows an endMessage to the user |
| children | node (list) | the data items which you need to scroll. |
| dataLength | number | set the length of the data.This will unlock the subsequent calls to next. |
| loader | node | you can send a loader component to show while the component waits for the next load of data. e.g. <h3>Loading...</h3> or any fancy loader element |
| scrollThreshold | number | string | A threshold value defining when InfiniteScroll will call next. Default value is 0.8. It means the next will be called when user comes below 80% of the total height. If you pass threshold in pixels (scrollThreshold="200px"), next will be called once you scroll at least (100% - scrollThreshold) pixels down. |
| onScroll | function | a function that will listen to the scroll event on the scrolling container. Note that the scroll event is throttled, so you may not receive as many events as you would expect. |
| endMessage | node | this message is shown to the user when he has seen all the records which means he's at the bottom and hasMore is false |
| className | string | add any custom class you want |
| style | object | any style which you want to override |
| height | number | optional, give only if you want to have a fixed height scrolling content |
| scrollableTarget | node or string | optional, reference to a (parent) DOM element that is already providing overflow scrollbars to the InfiniteScroll component. You should provide the id of the DOM node preferably. |
| hasChildren | bool | children is by default assumed to be of type array and it's length is used to determine if loader needs to be shown or not, if your children is not an array, specify this prop to tell if your items are 0 or more. |
| pullDownToRefresh | bool | to enable Pull Down to Refresh feature |
| pullDownToRefreshContent | node | any JSX that you want to show the user, default={<h3>Pull down to refresh</h3>} |
| releaseToRefreshContent | node | any JSX that you want to show the user, default={<h3>Release to refresh</h3>} |
| pullDownToRefreshThreshold | number | minimum distance the user needs to pull down to trigger the refresh, default=100px , a lower value may be needed to trigger the refresh depending your users browser. |
| refreshFunction | function | this function will be called, it should return the fresh data that you want to show the user |
| initialScrollY | number | set a scroll y position for the component to render with. |
| inverse | bool | set infinite scroll on top |
Thanks goes to these wonderful people (emoji key):
Ankeet Maini 💬 📖 💻 👀 🚧 | Darsh Shah 🚇 |
This project follows the all-contributors specification. Contributions of any kind are welcome!