react无限滚动列表实现
无限滚动列表实现方法
无限滚动列表(Infinite Scroll)是一种常见的UI模式,通过监听滚动事件动态加载更多数据,避免一次性渲染大量DOM节点。React中可通过以下方法实现:
使用Intersection Observer API
Intersection Observer是现代浏览器提供的API,可高效检测元素是否进入视口。
import { useState, useEffect, useRef } from 'react';
function InfiniteScrollList({ fetchData }) {
const [items, setItems] = useState([]);
const [page, setPage] = useState(1);
const loaderRef = useRef(null);
useEffect(() => {
const observer = new IntersectionObserver((entries) => {
if (entries[0].isIntersecting) {
loadMore();
}
});
if (loaderRef.current) {
observer.observe(loaderRef.current);
}
return () => observer.disconnect();
}, []);
const loadMore = async () => {
const newItems = await fetchData(page);
setItems(prev => [...prev, ...newItems]);
setPage(prev => prev + 1);
};
return (
<div>
{items.map(item => (
<div key={item.id}>{item.content}</div>
))}
<div ref={loaderRef}>Loading more...</div>
</div>
);
}
使用滚动事件监听
传统方法通过监听滚动事件计算位置,需注意性能优化。
import { useState, useEffect } from 'react';
function InfiniteScrollList({ fetchData }) {
const [items, setItems] = useState([]);
const [page, setPage] = useState(1);
const [loading, setLoading] = useState(false);
useEffect(() => {
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, [items]);
const handleScroll = () => {
if (
window.innerHeight + document.documentElement.scrollTop >=
document.documentElement.offsetHeight - 100 &&
!loading
) {
loadMore();
}
};
const loadMore = async () => {
setLoading(true);
const newItems = await fetchData(page);
setItems(prev => [...prev, ...newItems]);
setPage(prev => prev + 1);
setLoading(false);
};
return (
<div>
{items.map(item => (
<div key={item.id}>{item.content}</div>
))}
{loading && <div>Loading...</div>}
</div>
);
}
使用第三方库
现有成熟库如react-infinite-scroll-component可快速实现:
import InfiniteScroll from 'react-infinite-scroll-component';
function InfiniteScrollList({ fetchData }) {
const [items, setItems] = useState([]);
const [page, setPage] = useState(1);
const [hasMore, setHasMore] = useState(true);
const loadMore = async () => {
const newItems = await fetchData(page);
setItems(prev => [...prev, ...newItems]);
setPage(prev => prev + 1);
setHasMore(newItems.length > 0);
};
return (
<InfiniteScroll
dataLength={items.length}
next={loadMore}
hasMore={hasMore}
loader={<h4>Loading...</h4>}
>
{items.map(item => (
<div key={item.id}>{item.content}</div>
))}
</InfiniteScroll>
);
}
性能优化建议
- 对长列表使用虚拟滚动技术(如
react-window) - 避免在滚动事件中进行复杂计算
- 添加防抖/节流控制触发频率
- 确保每个列表项有稳定的key
- 考虑实现数据缓存机制
错误处理
- 添加加载失败重试机制
- 处理API请求错误情况
- 显示适当的空状态和错误提示







