feat: 创建无限滚动Hook │ │

│ │                                                                                                                                                   │ │
│ │ - 监听容器滚动事件                                                                                                                                │ │
│ │ - 距离底部阈值可配置(默认200px)                                                                                                                 │ │
│ │ - 自动触发onLoadMore回调                                                                                                                          │ │
│ │ - 支持加载状态管理
This commit is contained in:
zdl
2025-11-05 08:39:28 +08:00
parent 67127aa615
commit d96ebd6b8c

View File

@@ -0,0 +1,88 @@
// src/views/Community/components/DynamicNewsCard/hooks/useInfiniteScroll.js
// 无限滚动 Hook
import { useEffect, useRef, useCallback } from 'react';
/**
* 无限滚动 Hook
* 监听容器滚动事件,当滚动到底部附近时触发加载更多数据
*
* @param {Object} options - 配置选项
* @param {Function} options.onLoadMore - 加载更多回调函数(返回 Promise
* @param {boolean} options.hasMore - 是否还有更多数据
* @param {boolean} options.isLoading - 是否正在加载
* @param {number} options.threshold - 触发阈值距离底部多少像素时触发默认200px
* @returns {Object} { containerRef } - 容器引用
*/
export const useInfiniteScroll = ({
onLoadMore,
hasMore = true,
isLoading = false,
threshold = 200
}) => {
const containerRef = useRef(null);
const isLoadingRef = useRef(false);
// 滚动处理函数
const handleScroll = useCallback(() => {
const container = containerRef.current;
// 检查条件:容器存在、未加载中、还有更多数据
if (!container || isLoadingRef.current || !hasMore) {
return;
}
const { scrollTop, scrollHeight, clientHeight } = container;
const distanceToBottom = scrollHeight - scrollTop - clientHeight;
// 距离底部小于阈值时触发加载
if (distanceToBottom < threshold) {
console.log(
'%c⬇ [懒加载] 触发加载下一页',
'color: #8B5CF6; font-weight: bold;',
{
scrollTop,
scrollHeight,
clientHeight,
distanceToBottom,
threshold
}
);
isLoadingRef.current = true;
// 调用加载函数并更新状态
onLoadMore()
.then(() => {
console.log('%c✅ [懒加载] 加载完成', 'color: #10B981; font-weight: bold;');
})
.catch((error) => {
console.error('%c❌ [懒加载] 加载失败', 'color: #DC2626; font-weight: bold;', error);
})
.finally(() => {
isLoadingRef.current = false;
});
}
}, [onLoadMore, hasMore, threshold]);
// 绑定滚动事件
useEffect(() => {
const container = containerRef.current;
if (!container) return;
// 添加滚动监听
container.addEventListener('scroll', handleScroll, { passive: true });
// 清理函数
return () => {
container.removeEventListener('scroll', handleScroll);
};
}, [handleScroll]);
// 更新 loading 状态的 ref
useEffect(() => {
isLoadingRef.current = isLoading;
}, [isLoading]);
return { containerRef };
};