diff --git a/src/app/tools/tank-performance/components/RowLoader.tsx b/src/app/tools/tank-performance/components/RowLoader.tsx index 09ebbab69..7f199226c 100644 --- a/src/app/tools/tank-performance/components/RowLoader.tsx +++ b/src/app/tools/tank-performance/components/RowLoader.tsx @@ -1,6 +1,7 @@ import { Skeleton, Table } from '@radix-ui/themes'; import { times } from 'lodash'; -import { useEffect, useRef } from 'react'; +import { useRef } from 'react'; +import { useIntersection } from '../../../../hooks/useIntersection'; import { tankPerformanceSortTypeNamesArray } from '../../../../stores/tankPerformanceSort'; interface RowLoaderProps { @@ -10,14 +11,9 @@ interface RowLoaderProps { export function RowLoader({ onIntersection }: RowLoaderProps) { const row = useRef(null); - useEffect(() => { - if (!onIntersection || !row.current) return; - - const observer = new IntersectionObserver(onIntersection); - observer.observe(row.current); - - return () => observer.disconnect(); - }, []); + useIntersection(() => onIntersection?.(), row, { + disabled: onIntersection === undefined, + }); return ( diff --git a/src/app/tools/tank-performance/components/Tanks.tsx b/src/app/tools/tank-performance/components/Tanks.tsx index 02a82989b..859d1cb19 100644 --- a/src/app/tools/tank-performance/components/Tanks.tsx +++ b/src/app/tools/tank-performance/components/Tanks.tsx @@ -134,16 +134,9 @@ export function Tanks() { return ( { - console.log('Intersected'); - setLoadedRows((state) => - Math.min(state + PREVIEW_COUNT, tanks.length), - ); - } - : undefined - } + onIntersection={() => { + setLoadedRows((state) => Math.min(state + 2, tanks.length)); + }} /> ); })} diff --git a/src/hooks/useIntersection.ts b/src/hooks/useIntersection.ts new file mode 100644 index 000000000..2f2422f23 --- /dev/null +++ b/src/hooks/useIntersection.ts @@ -0,0 +1,31 @@ +import { RefObject, useLayoutEffect, useRef } from 'react'; + +interface UseIntersectionOptions extends IntersectionObserverInit { + disabled: boolean; +} + +export function useIntersection( + callback: () => void, + ref: RefObject, + options?: UseIntersectionOptions, +) { + const observer = useRef(); + + useLayoutEffect(() => { + if (options?.disabled || !ref.current) return; + + const rect = ref.current.getBoundingClientRect(); + const visible = !(rect.bottom < 0 || rect.top - window.innerHeight >= 0); + + if (visible) { + callback(); + } else { + observer.current = new IntersectionObserver(callback, options); + observer.current.observe(ref.current); + + return () => observer.current!.disconnect(); + } + }, []); + + return observer; +}