All files / src/hooks useInfiniteScroll.ts

100% Statements 24/24
87.5% Branches 7/8
100% Functions 2/2
100% Lines 24/24

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 411x                             1x 10x 10x 10x 10x 10x 10x   10x 10x 10x 10x 10x 5x 2x 2x 5x 10x 10x 10x 10x 10x   10x 10x  
import { useEffect, useRef } from 'react';
 
interface UseInfiniteScrollOptions {
  hasNextPage: boolean;
  isFetchingNextPage: boolean;
  fetchNextPage: () => void;
  rootMargin?: string;
}
 
/**
 * Attaches an IntersectionObserver to a sentinel element.
 * Calls fetchNextPage when the sentinel scrolls into the viewport.
 *
 * @returns ref — attach to the sentinel <div> at the bottom of the list
 */
export const useInfiniteScroll = ({
  hasNextPage,
  isFetchingNextPage,
  fetchNextPage,
  rootMargin = '300px',
}: UseInfiniteScrollOptions) => {
  const sentinelRef = useRef<HTMLDivElement | null>(null);
 
  useEffect(() => {
    const node = sentinelRef.current;
    if (!node) return;
    const observer = new IntersectionObserver(
      (entries) => {
        if (entries[0]?.isIntersecting && hasNextPage && !isFetchingNextPage) {
          fetchNextPage();
        }
      },
      { rootMargin },
    );
    observer.observe(node);
    return () => observer.disconnect();
  }, [hasNextPage, isFetchingNextPage, fetchNextPage, rootMargin]);
 
  return sentinelRef;
};