react-infinite-scroll-component
是一个非常实用的 React 组件,用来实现 无限滚动加载,常见的场景就是列表/卡片/瀑布流等下拉触底自动加载更多。
1. 安装
sql
npm install react-infinite-scroll-component
# 或者
yarn add react-infinite-scroll-component
2. 基本使用
最简单的使用方法是包裹一个列表:
javascript
import React, { useState } from "react";
import InfiniteScroll from "react-infinite-scroll-component";
export default function Demo() {
const [items, setItems] = useState(Array.from({ length: 20 }));
const fetchMoreData = () => {
// 模拟异步请求
setTimeout(() => {
setItems((prev) => [
...prev,
...Array.from({ length: 20 }) // 追加 20 条数据
]);
}, 1500);
};
return (
<div>
<h1>Infinite Scroll Example</h1>
<InfiniteScroll
dataLength={items.length} // 当前列表长度
next={fetchMoreData} // 加载更多的方法
hasMore={true} // 是否还有更多数据
loader={<h4>加载中...</h4>} // 加载时的占位
endMessage={<p style={{ textAlign: "center" }}>没有更多了 🎉</p>} // 没有数据时提示
>
{items.map((_, index) => (
<div
key={index}
style={{
height: 50,
border: "1px solid #ccc",
margin: 6,
padding: 8
}}
>
Item #{index}
</div>
))}
</InfiniteScroll>
</div>
);
}
3. 关键属性说明
-
dataLength
当前列表的长度,必须正确设置,否则组件不会触发
next
。 -
next
加载更多的方法(一般是异步请求接口)。
-
hasMore
布尔值,表示是否还有更多数据。如果为
false
,会显示endMessage
。 -
loader
加载时展示的内容,比如
loading...
。 -
endMessage
当没有更多数据时显示的内容。
-
scrollableTarget
如果滚动容器不是
window
,需要设置一个 容器的 id。ini<div id="scrollableDiv" style={{ height: 400, overflow: "auto" }}> <InfiniteScroll dataLength={items.length} next={fetchMoreData} hasMore={true} loader={<h4>Loading...</h4>} scrollableTarget="scrollableDiv" // 指定容器 > {/* 列表 */} </InfiniteScroll> </div>
4. 常见问题
-
为什么
next
不触发?- 一般是
dataLength
没有写对。 - 或者外层容器高度不足,导致不触发滚动事件。
- 一般是
-
如何在接口没数据时停止加载?
- 请求接口时判断是否还有数据,然后设置
hasMore = false
。
- 请求接口时判断是否还有数据,然后设置
-
如果 第一次加载的数据太少,容器内容高度不够撑满滚动区域 ,那就根本滚不动,也就无法触发
next()
了。
方案 1:设置容器固定高度
给容器一个固定高度 + overflow: auto
,这样即使数据很少,也会有一个可滚动的区域。
ini
<div
id="scrollableDiv"
style={{
height: 400, // 固定高度
overflow: "auto"
}}
>
<InfiniteScroll
dataLength={items.length}
next={fetchMoreData}
hasMore={true}
loader={<h4>Loading...</h4>}
scrollableTarget="scrollableDiv"
>
{items.map((item, index) => (
<div key={index}>{item}</div>
))}
</InfiniteScroll>
</div>
方案 2:初始多加载几条
在首次请求时多拿一些数据(比如 20 条),保证能撑满容器。
- 缺点:有时候数据量太大会影响首屏性能。
- 适合内容较轻、接口响应快的场景。
方案 3:初始加载不足时,手动继续加载
你可以在 useEffect
里判断:如果内容高度 小于容器高度 ,那就直接调用一次 next()
,直到撑满为止。
示例:
scss
useEffect(() => {
const container = document.getElementById("scrollableDiv");
if (container && container.scrollHeight <= container.clientHeight) {
fetchMoreData(); // 自动再拉一次数据
}
}, [items]);
这样即使第一次数据少,也能自动补齐到能滚动。
方案 4:改用虚拟列表库
如果数据量特别大,不用 react-infinite-scroll-component
,可以直接上 虚拟滚动库 (比如 react-window
、react-virtualized
),它们能更好处理 小数据首屏 + 大数据无限加载 的问题。
✅ 总结:
- 如果容器是
window
:要么让首屏数据足够多,要么在首屏时主动拉几次数据。 - 如果容器是
div
:给定高度,配合useEffect
判断不够高时自动加载。
与rc-virtual-list组件区别
1. react-infinite-scroll-component
🔹 核心功能 :无限滚动加载
- 关注点是 什么时候触底,去触发 next() 请求更多数据
- 它会把数据一条条 直接渲染到 DOM,不会做虚拟化
- 每次都是真实 DOM 节点增加,数据越多 → DOM 越大 → 性能越差
适用场景:
- 数据量不算特别大(几百条以内)
- 重点是"自动触发加载更多"逻辑
- 列表项样式高度不固定也没问题
2. rc-virtual-list(虚拟列表)
🔹 核心功能 :虚拟化渲染
- 关注点是 只渲染可视区的元素,不在屏幕上的元素直接移除
- 对外表现是一个大列表,但实际 DOM 节点数只有几十个
- 没有内置"无限加载"的功能(需要自己监听滚动 + 请求数据,再更新 list)
- 对性能极好,数据量上万条也不卡
适用场景:
- 数据量非常大(成千上万条)
- 对滚动性能要求高
- 可结合分页/懒加载自己实现"无限加载"
3. 对比总结
特性 | react-infinite-scroll-component | rc-virtual-list |
---|---|---|
核心目标 | 无限加载 | 高性能虚拟渲染 |
滚动监听 | 内置 hasMore + next |
需要自己处理 |
性能 | 大量数据时性能差(DOM 持续增加) | 高性能(只渲染可视区) |
使用复杂度 | 简单,拿来即用 | 稍复杂,需要自己结合分页加载 |
数据量适合 | 小到中等(几百到几千条) | 超大数据量(几万甚至更多) |
item 高度 | 自由(可不固定) | 一般要求 item 高度固定或可计算 |
4. 如何选择?
- 数据量小(几百条),要快速实现无限加载 👉 用
react-infinite-scroll-component
- 数据量大(几千上万条),性能要求高 👉 用
rc-virtual-list
(再手动实现无限加载逻辑) - 数据量中等,但既要无限加载又要虚拟化 👉 可以把 虚拟列表库 和 无限加载逻辑 结合使用(比如在
rc-virtual-list
的 onScroll 里判断触底,触发加载)。