react实现分页滚动加载
实现分页滚动加载的基本思路
分页滚动加载(无限滚动)的核心逻辑是监听滚动事件,当用户滚动到接近页面底部时触发数据加载。React中可以通过结合useEffect和DOM事件监听实现。
监听滚动事件并触发加载
在React组件中,通过useEffect添加滚动事件监听器,计算是否到达页面底部:
useEffect(() => {
const handleScroll = () => {
const { scrollTop, clientHeight, scrollHeight } = document.documentElement;
if (scrollTop + clientHeight >= scrollHeight - 10) {
loadMoreData();
}
};
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, []);
数据加载逻辑
实现异步加载数据的函数,通常需要维护当前页码和加载状态:
const [data, setData] = useState([]);
const [page, setPage] = useState(1);
const [loading, setLoading] = useState(false);
const loadMoreData = async () => {
if (loading) return;
setLoading(true);
try {
const newData = await fetchData(page); // 替换为实际API调用
setData(prev => [...prev, ...newData]);
setPage(prev => prev + 1);
} finally {
setLoading(false);
}
};
优化性能与体验
使用Intersection Observer API替代传统滚动监听,性能更好:
useEffect(() => {
const observer = new IntersectionObserver(
(entries) => {
if (entries[0].isIntersecting) {
loadMoreData();
}
},
{ threshold: 1.0 }
);
if (loaderRef.current) {
observer.observe(loaderRef.current);
}
return () => observer.disconnect();
}, [loading]);
在页面底部添加一个哨兵元素作为观察节点:
<div ref={loaderRef}>
{loading && <p>Loading more data...</p>}
</div>
完整组件示例
import React, { useState, useEffect, useRef } from 'react';
function InfiniteScrollList() {
const [items, setItems] = useState([]);
const [page, setPage] = useState(1);
const [loading, setLoading] = useState(false);
const loaderRef = useRef(null);
const fetchItems = async (pageNum) => {
// 模拟API请求
return new Array(10).fill(0).map((_, i) =>
`Item ${(pageNum - 1) * 10 + i + 1}`
);
};
const loadMore = async () => {
if (loading) return;
setLoading(true);
try {
const newItems = await fetchItems(page);
setItems(prev => [...prev, ...newItems]);
setPage(prev => prev + 1);
} finally {
setLoading(false);
}
};
useEffect(() => {
const observer = new IntersectionObserver(
(entries) => {
if (entries[0].isIntersecting) {
loadMore();
}
},
{ threshold: 1.0 }
);
if (loaderRef.current) {
observer.observe(loaderRef.current);
}
return () => observer.disconnect();
}, [loading]);
return (
<div>
{items.map((item, index) => (
<div key={index} style={{ padding: '20px', border: '1px solid #ccc' }}>
{item}
</div>
))}
<div ref={loaderRef}>
{loading && <p>Loading...</p>}
</div>
</div>
);
}
export default InfiniteScrollList;
注意事项
- 添加防抖逻辑避免频繁触发加载
- 处理API请求错误情况
- 在组件卸载时清除事件监听器
- 考虑移动端兼容性
- 实现数据加载完毕后的终止逻辑(无更多数据时)
使用现成库的方案
如需快速实现,可以考虑使用现成的React无限滚动库:
npm install react-infinite-scroll-component
示例用法:
import InfiniteScroll from 'react-infinite-scroll-component';
function InfiniteScrollComponent() {
// ...状态管理逻辑同上
return (
<InfiniteScroll
dataLength={items.length}
next={loadMore}
hasMore={true}
loader={<h4>Loading...</h4>}
>
{items.map((item, index) => (
<div key={index}>{item}</div>
))}
</InfiniteScroll>
);
}






