| | import throttle from 'lodash/throttle'; |
| | import React, { useCallback, useEffect, useRef } from 'react'; |
| | import type { FetchNextPageOptions, InfiniteQueryObserverResult } from '@tanstack/react-query'; |
| |
|
| | export default function useNavScrolling<TData>({ |
| | nextCursor, |
| | isFetchingNext, |
| | setShowLoading, |
| | fetchNextPage, |
| | }: { |
| | nextCursor?: string | null; |
| | isFetchingNext: boolean; |
| | setShowLoading: React.Dispatch<React.SetStateAction<boolean>>; |
| | fetchNextPage?: ( |
| | options?: FetchNextPageOptions | undefined, |
| | ) => Promise<InfiniteQueryObserverResult<TData, unknown>>; |
| | }) { |
| | const scrollPositionRef = useRef<number | null>(null); |
| | const containerRef = useRef<HTMLDivElement | null>(null); |
| |
|
| | |
| | const fetchNext = useCallback( |
| | throttle( |
| | () => { |
| | if (fetchNextPage) { |
| | return fetchNextPage(); |
| | } |
| | return Promise.resolve(); |
| | }, |
| | 750, |
| | { leading: true }, |
| | ), |
| | [fetchNextPage], |
| | ); |
| |
|
| | const handleScroll = useCallback(() => { |
| | if (containerRef.current) { |
| | const { scrollTop, clientHeight, scrollHeight } = containerRef.current; |
| | const nearBottomOfList = scrollTop + clientHeight >= scrollHeight * 0.97; |
| |
|
| | if (nearBottomOfList && nextCursor != null && !isFetchingNext) { |
| | setShowLoading(true); |
| | fetchNext(); |
| | } else { |
| | setShowLoading(false); |
| | } |
| | } |
| | }, [nextCursor, isFetchingNext, fetchNext, setShowLoading]); |
| |
|
| | useEffect(() => { |
| | const container = containerRef.current; |
| | if (container) { |
| | container.addEventListener('scroll', handleScroll); |
| | } |
| |
|
| | return () => { |
| | if (container) { |
| | container.removeEventListener('scroll', handleScroll); |
| | } |
| | }; |
| | }, [handleScroll]); |
| |
|
| | const moveToTop = useCallback(() => { |
| | const container = containerRef.current; |
| | if (container) { |
| | scrollPositionRef.current = container.scrollTop; |
| | } |
| | }, []); |
| |
|
| | return { |
| | containerRef, |
| | moveToTop, |
| | }; |
| | } |
| |
|