Files
eranos/src/hooks/useInfiniteScroll.ts
T
Chad Curtis 6dd29c571f refactor: extract useInfiniteScroll hook and deduplicateEvents utility
Consolidate duplicated infinite-scroll boilerplate (auto-fetch page 2,
IntersectionObserver, scroll trigger) into a shared useInfiniteScroll
hook, and extract the flatten+dedup pattern into deduplicateEvents.

Also migrate BadgesPage and ThemesPage to use useFeedTab for
consistent tab persistence across all feed pages.
2026-03-28 05:31:49 -05:00

55 lines
1.6 KiB
TypeScript

import { useEffect } from 'react';
import { useInView } from 'react-intersection-observer';
interface UseInfiniteScrollOptions {
/** Whether there are more pages to fetch. */
hasNextPage: boolean;
/** Whether a page is currently being fetched. */
isFetchingNextPage: boolean;
/** Trigger fetching the next page. */
fetchNextPage: () => void;
/** Number of pages already loaded (used to auto-fetch page 2). */
pageCount: number | undefined;
/** Disable scrolling (useful when a non-feed tab is active). */
enabled?: boolean;
}
/**
* Encapsulates the infinite-scroll boilerplate shared by feed pages:
*
* 1. Auto-fetches page 2 as soon as page 1 arrives for smoother scrolling.
* 2. Sets up an IntersectionObserver that triggers `fetchNextPage` when the
* sentinel element scrolls into view.
*
* Returns `scrollRef` — attach it to a sentinel `<div>` near the bottom of
* the list.
*/
export function useInfiniteScroll({
hasNextPage,
isFetchingNextPage,
fetchNextPage,
pageCount,
enabled = true,
}: UseInfiniteScrollOptions) {
// Auto-fetch page 2 as soon as page 1 arrives
useEffect(() => {
if (enabled && hasNextPage && !isFetchingNextPage && pageCount === 1) {
fetchNextPage();
}
}, [enabled, hasNextPage, isFetchingNextPage, pageCount, fetchNextPage]);
// Intersection observer for infinite scroll
const { ref: scrollRef, inView } = useInView({
threshold: 0,
rootMargin: '400px',
});
useEffect(() => {
if (inView && hasNextPage && !isFetchingNextPage) {
fetchNextPage();
}
}, [inView, hasNextPage, isFetchingNextPage, fetchNextPage]);
return { scrollRef };
}