react 上拉加载 实现
实现 React 上拉加载的步骤
使用 Intersection Observer API
通过监听目标元素与视口的交叉状态,触发加载更多数据的逻辑。
import React, { useEffect, useRef, useState } from 'react';
function InfiniteScroll() {
const [items, setItems] = useState([]);
const [page, setPage] = useState(1);
const loaderRef = useRef(null);
useEffect(() => {
const observer = new IntersectionObserver(
(entries) => {
if (entries[0].isIntersecting) {
loadMoreData();
}
},
{ threshold: 1.0 }
);
if (loaderRef.current) {
observer.observe(loaderRef.current);
}
return () => {
if (loaderRef.current) {
observer.unobserve(loaderRef.current);
}
};
}, []);
const loadMoreData = async () => {
const newData = await fetchData(page);
setItems(prev => [...prev, ...newData]);
setPage(prev => prev + 1);
};
return (
<div>
{items.map(item => (
<div key={item.id}>{item.content}</div>
))}
<div ref={loaderRef}>Loading...</div>
</div>
);
}
使用滚动事件监听
通过监听滚动事件,计算滚动位置来触发加载。
import React, { useEffect, useState } from 'react';
function ScrollLoad() {
const [items, setItems] = useState([]);
const [page, setPage] = useState(1);
const [loading, setLoading] = useState(false);
useEffect(() => {
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, []);
const handleScroll = () => {
if (
window.innerHeight + document.documentElement.scrollTop !==
document.documentElement.offsetHeight ||
loading
) {
return;
}
loadMoreData();
};
const loadMoreData = async () => {
setLoading(true);
const newData = await fetchData(page);
setItems(prev => [...prev, ...newData]);
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 App() {
const [items, setItems] = useState([]);
const [page, setPage] = useState(1);
const [hasMore, setHasMore] = useState(true);
const fetchMoreData = async () => {
const newData = await fetchData(page);
if (newData.length === 0) {
setHasMore(false);
return;
}
setItems(prev => [...prev, ...newData]);
setPage(prev => prev + 1);
};
return (
<InfiniteScroll
dataLength={items.length}
next={fetchMoreData}
hasMore={hasMore}
loader={<h4>Loading...</h4>}
>
{items.map(item => (
<div key={item.id}>{item.content}</div>
))}
</InfiniteScroll>
);
}
注意事项
确保在组件卸载时清除事件监听或 Intersection Observer,避免内存泄漏。
加载数据时添加加载状态,防止重复请求。

根据实际需求调整触发加载的阈值或条件。






