feat: 🎸 重新封装了滚动加载/解决了一个引用bug

This commit is contained in:
2025-08-21 13:37:27 +08:00
parent 52572dfdeb
commit 916d210290
3 changed files with 63 additions and 36 deletions

View File

@@ -6,41 +6,61 @@ const InfiniteScroll = ({
loadMore,
hasMore,
children,
threshold = 50,
threshold = 0.1, // 触发阈值,元素可见比例
className = "",
empty = false,
}) => {
const containerRef = useRef(null);
const sentinelRef = useRef(null);
const observerRef = useRef(null);
const [loading, setLoading] = useState(false);
const [hasInitialized, setHasInitialized] = useState(false); // 首次挂载
// 加载更多数据的处理函数
const handleLoadMore = () => {
if (loading || !hasMore) return;
const handleScroll = () => {
if (loading) return;
setLoading(true);
if (!containerRef.current || !hasMore) return;
const { scrollTop, scrollHeight, clientHeight } = containerRef.current;
if (scrollTop + clientHeight >= scrollHeight - threshold) {
loadMore().finally(() => {
setLoading(false);
});
}
loadMore().finally(() => {
setLoading(false);
});
};
// 设置IntersectionObserver
useEffect(() => {
const container = containerRef.current;
if (container) {
container.addEventListener("scroll", handleScroll);
// 初始加载时检查是否需要加载更多
handleScroll();
// 初始化观察器
const options = {
root: containerRef.current,
rootMargin: "0px 0px 50px 0px", // 减少提前触发距离
threshold,
};
// 创建观察器实例
observerRef.current = new IntersectionObserver((entries) => {
const [entry] = entries;
if (entry.isIntersecting) {
handleLoadMore();
}
}, options);
// 开始观察哨兵元素
if (sentinelRef.current) {
observerRef.current.observe(sentinelRef.current);
}
// 初始加载检查 - 仅在组件首次挂载时执行
if (hasMore && !loading && !hasInitialized) {
setHasInitialized(true);
handleLoadMore();
}
// 清理函数
return () => {
if (container) {
container.removeEventListener("scroll", handleScroll);
if (observerRef.current) {
observerRef.current.disconnect();
}
};
}, [loadMore, hasMore, threshold]);
}, [loadMore, hasMore, threshold, loading]);
return (
<div
@@ -49,6 +69,9 @@ const InfiniteScroll = ({
>
{children}
{/* 哨兵元素 - 用于触发加载更多 */}
<div ref={sentinelRef} className="sentinel-element"></div>
{!hasMore && empty && (
<Empty description="暂无数据" className="empty-data" />
)}