react-infinite-scroll-component 是一个用于在 React 应用中实现无限滚动(Infinite Scroll)功能的轻量级组件库。它允许开发者在用户滚动到容器底部时自动加载更多内容,常用于长列表、消息流或分页数据的懒加载场景。该组件封装了滚动事件监听、加载状态管理以及占位符渲染等逻辑,简化了无限滚动的实现复杂度。
在本次比较中,您提供的两个包名均为 react-infinite-scroll-component —— 这是同一个 npm 包被重复列出,并非两个不同的库。因此,不存在技术差异或选型问题。但我们仍可借此机会深入剖析该库的实际能力、适用边界和潜在陷阱,帮助专业开发者判断是否应在新项目中采用它。
react-infinite-scroll-component 的核心是一个 React 组件,通过监听滚动事件,在用户接近容器底部时触发 next() 回调以加载更多数据。它内置了加载中提示(如 spinner)和“无更多数据”状态的 UI 管理。
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>加载中...</h4>}
scrollableTarget="scrollableDiv"
>
{items.map(item => <div key={item.id}>{item.name}</div>)}
</InfiniteScroll>
</div>
);
}
关键属性说明:
dataLength:当前已加载的数据项数量,用于判断是否触发加载。next:加载下一页数据的函数。hasMore:布尔值,表示是否还有更多数据可加载。loader:加载中的占位元素。scrollableTarget:可选,指定滚动容器的 ID(默认监听 window 滚动)。尽管该组件上手简单,但在真实项目中需警惕以下限制:
该库无法处理水平无限滚动场景。如果你的 UI 需要横向滑动加载(如图片轮播、时间轴),此库不适用。
通过 scrollableTarget 指定滚动容器时,必须传入字符串 ID。这在动态生成的组件或严格遵循 React ref 模式的现代代码中显得笨拙,且容易因 ID 冲突导致行为异常。
// 不推荐:硬编码 ID,难以复用
<div id="my-list-container">
<InfiniteScroll scrollableTarget="my-list-container" ... />
</div>
相比之下,更现代的方案(如 react-intersection-observer + 自定义逻辑)可直接使用 React refs,避免全局 ID 依赖。
该组件未内置虚拟滚动(virtualization)支持。当列表项数量极大(如上千条)时,DOM 节点过多会导致内存占用高、滚动卡顿。此时应考虑 react-window 或 react-virtual 等结合无限滚动的方案。
加载失败时,组件不会自动提供“重试”按钮或错误状态反馈。开发者需自行在外层管理加载状态和错误恢复逻辑,增加了业务复杂度。
// 需手动处理错误状态
const [error, setError] = useState(null);
const loadMore = async () => {
try {
await fetchData();
setError(null);
} catch (err) {
setError(err);
}
};
// 在 loader 中额外渲染错误提示
{error && <button onClick={loadMore}>重试</button>}
截至最新验证,react-infinite-scroll-component 在 npm 和 GitHub 上未被官方标记为废弃(deprecated),但其最近一次显著更新已较为久远,且 issue 区存在若干未解决的兼容性问题(如与 Strict Mode 冲突)。对于新项目,建议评估以下替代路径:
IntersectionObserver API 监听底部哨兵元素,代码量少且完全可控。function useInfiniteScroll(callback) {
const sentinelRef = useRef();
useEffect(() => {
const observer = new IntersectionObserver(entries => {
if (entries[0].isIntersecting) callback();
});
if (sentinelRef.current) observer.observe(sentinelRef.current);
return () => observer.disconnect();
}, [callback]);
return sentinelRef;
}
// 使用
const sentinelRef = useInfiniteScroll(loadMore);
return (
<>
{items.map(item => <div key={item.id}>{item.name}</div>)}
<div ref={sentinelRef} />
</>
);
react-waypoint(通用滚动触发点)或结合 react-query 的分页 hooks,可获得更好的状态管理和缓存能力。虽然 react-infinite-scroll-component 提供了简洁的 API,但其设计较为陈旧,缺乏现代 React 应用所需的灵活性和健壮性。在新项目中,除非需求极其简单,否则建议优先考虑基于 IntersectionObserver 的自定义方案或更活跃维护的替代库。对于已有项目中正在使用的实例,若运行稳定,可继续维护,但应避免在新模块中扩展其使用范围。
由于所列两个包名完全相同,实际指向同一个 npm 包 react-infinite-scroll-component,因此不存在选型差异。若项目需要简单、开箱即用的无限滚动功能,且数据源为垂直方向的线性列表,可直接使用此包。但需注意其不支持水平滚动、自定义滚动容器(仅限 window 或指定 DOM 容器)等高级场景,且长期未有重大更新,建议评估是否满足当前项目需求。
由于所列两个包名完全相同,实际指向同一个 npm 包 react-infinite-scroll-component,因此不存在选型差异。若项目需要简单、开箱即用的无限滚动功能,且数据源为垂直方向的线性列表,可直接使用此包。但需注意其不支持水平滚动、自定义滚动容器(仅限 window 或指定 DOM 容器)等高级场景,且长期未有重大更新,建议评估是否满足当前项目需求。
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!