diff --git a/package-lock.json b/package-lock.json index ebcefd0..0295ccf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@worksolutions/react-utils", - "version": "2.2.4", + "version": "2.2.5", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@worksolutions/react-utils", - "version": "2.2.4", + "version": "2.2.5", "dependencies": { "@popperjs/core": "^2.*", "@worksolutions/utils": "^1.4.3", diff --git a/package.json b/package.json index 1fec9d1..945da17 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@worksolutions/react-utils", "private": false, - "version": "2.2.4", + "version": "2.2.5", "description": "", "types": "dist/esm/index.d.ts", "main": "dist/cjs/index.js", diff --git a/src/hooks/useInfinityScroll.ts b/src/hooks/useInfinityScroll.ts index 4cea636..f9939a6 100644 --- a/src/hooks/useInfinityScroll.ts +++ b/src/hooks/useInfinityScroll.ts @@ -7,7 +7,9 @@ import { useSyncToRef } from "./useSyncToRef"; type UseInfiniteScrollDirection = "down" | "up"; interface UseInfinityScrollConfig { - loading: boolean; + loading?: boolean; + loadingRef?: React.MutableRefObject; + waitLoadingMS?: number; hasNextPage: boolean; threshold?: number; startObservingDelay?: number; @@ -36,14 +38,21 @@ const scrollRemainderDetectors = { export function useInfinityScroll({ scrollCheckInterval = 200, threshold = 200, - loading, + waitLoadingMS, + loading: incomeLoading, + loadingRef: incomeLoadingRef, startObservingDelay = 0, direction = "down", hasNextPage, onLoadMore, }: UseInfinityScrollConfig) { - const [scrollableElement, setScrollableElement] = React.useState(null); - const loadingRef = useSyncToRef(loading); + const [scrollableElement, setScrollableElement] = React.useState(null); + + const loadingRef1 = incomeLoadingRef; + const loadingRef2 = useSyncToRef(incomeLoading); + + const loadingRef = useSyncToRef(loadingRef1?.current ?? loadingRef2.current ?? false); + const hasNextPageRef = useSyncToRef(hasNextPage); const onLoadMoreRef = useSyncToRef(onLoadMore); @@ -53,6 +62,7 @@ export function useInfinityScroll({ startObservingDelay, scrollCheckInterval, direction, + waitLoadingMS, hasNextPage: hasNextPageRef, loading: loadingRef, onLoadMore: onLoadMoreRef, @@ -73,6 +83,7 @@ function useScrollListener({ scrollableElement, hasNextPage, loading, + waitLoadingMS, threshold, direction, onLoadMore, @@ -86,16 +97,24 @@ function useScrollListener({ direction: UseInfiniteScrollDirection; hasNextPage: React.MutableRefObject; loading: React.MutableRefObject; + waitLoadingMS: number | undefined; onLoadMore: React.MutableRefObject<() => void>; }) { React.useEffect(() => { if (!scrollableElement) return () => null; + let waitLoadingTimer: NodeJS.Timeout | null = null; + const listener = throttle(function () { if (!hasNextPage.current || loading.current) return; const scrollToEnd = scrollRemainderDetectors[direction](scrollableElement); if (scrollToEnd > threshold) return; - onLoadMore.current(); + if (waitLoadingMS === undefined) return onLoadMore.current(); + clearTimeout(waitLoadingTimer!); + waitLoadingTimer = setTimeout(() => { + if (loading.current) return; + onLoadMore.current(); + }, waitLoadingMS); }, scrollCheckInterval); const startObservingTimeout = setTimeout( @@ -116,6 +135,7 @@ function useScrollListener({ scrollCheckInterval, scrollableElement, threshold, + waitLoadingMS, ]); } diff --git a/src/hooks/useSyncToRef.ts b/src/hooks/useSyncToRef.ts index ce1d3a8..d31ab85 100644 --- a/src/hooks/useSyncToRef.ts +++ b/src/hooks/useSyncToRef.ts @@ -1,10 +1,8 @@ import React from "react"; -import { useEffectSkipFirst } from "./common"; - export function useSyncToRef(data: T) { const ref = React.useRef(data); - useEffectSkipFirst(() => { + React.useMemo(() => { ref.current = data; }, [data]); return ref;