diff --git a/src/views/Community/components/DynamicNewsCard/hooks/useInfiniteScroll.js b/src/views/Community/components/DynamicNewsCard/hooks/useInfiniteScroll.js new file mode 100644 index 00000000..17ccfb8c --- /dev/null +++ b/src/views/Community/components/DynamicNewsCard/hooks/useInfiniteScroll.js @@ -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 }; +};