react实现滚动分页
实现滚动分页的基本思路
滚动分页(Infinite Scroll)的核心是通过监听滚动事件,在用户接近页面底部时自动加载更多数据。React中通常结合Intersection Observer API或手动计算滚动位置实现。
使用Intersection Observer API
Intersection Observer是现代浏览器提供的API,性能优于手动监听滚动事件。

import { useState, useEffect, useRef } from 'react';
function InfiniteScrollList() {
const [items, setItems] = useState([]);
const [page, setPage] = useState(1);
const loaderRef = useRef(null);
useEffect(() => {
const observer = new IntersectionObserver(
(entries) => {
if (entries[0].isIntersecting) {
loadMoreItems();
}
},
{ threshold: 1.0 }
);
if (loaderRef.current) {
observer.observe(loaderRef.current);
}
return () => observer.disconnect();
}, []);
const loadMoreItems = async () => {
const newItems = await fetchItems(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 items...</div>
</div>
);
}
手动监听滚动事件
兼容性更好的传统方法,需注意防抖(debounce)优化:

import { useState, useEffect } from 'react';
function InfiniteScrollList() {
const [items, setItems] = useState([]);
const [page, setPage] = useState(1);
const [loading, setLoading] = useState(false);
useEffect(() => {
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, [loading]);
const handleScroll = () => {
if (
window.innerHeight + document.documentElement.scrollTop !==
document.documentElement.offsetHeight ||
loading
) {
return;
}
loadMoreItems();
};
const loadMoreItems = async () => {
setLoading(true);
const newItems = await fetchItems(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() {
const [items, setItems] = useState([]);
const [page, setPage] = useState(1);
const [hasMore, setHasMore] = useState(true);
const fetchMoreData = async () => {
const newItems = await fetchItems(page);
if (newItems.length === 0) setHasMore(false);
setItems(prev => [...prev, ...newItems]);
setPage(prev => prev + 1);
};
return (
<InfiniteScroll
dataLength={items.length}
next={fetchMoreData}
hasMore={hasMore}
loader={<h4>Loading...</h4>}
>
{items.map((item, index) => (
<div key={index}>{item.content}</div>
))}
</InfiniteScroll>
);
}
性能优化建议
- 添加防抖逻辑避免频繁触发加载
- 在组件卸载时清除事件监听
- 实现数据缓存避免重复请求
- 对长列表使用
react-window或react-virtualized虚拟滚动
错误处理
需考虑网络请求失败的情况:
const loadMoreItems = async () => {
try {
setLoading(true);
const newItems = await fetchItems(page);
setItems(prev => [...prev, ...newItems]);
setPage(prev => prev + 1);
} catch (error) {
console.error('Failed to load items:', error);
} finally {
setLoading(false);
}
};






