Last active
April 16, 2025 10:39
-
-
Save owaisahmed5300/454652bb02059a1e1b55d5ad398501c2 to your computer and use it in GitHub Desktop.
React Infinite Scroll Typescript Intersection Observer
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import {FC, ReactNode, useCallback, useEffect, useRef} from "react"; | |
interface InfiniteScrollProps { | |
load: () => void; | |
hasMore: boolean; | |
loader: ReactNode; | |
children?: ReactNode; | |
endMessage?: ReactNode; | |
} | |
export const InfiniteScroll: FC<InfiniteScrollProps> = ({ | |
load, | |
hasMore, | |
loader, | |
children, | |
endMessage, | |
}) => { | |
const sentinelRef = useRef<HTMLDivElement>(null); | |
const observerRef = useRef<IntersectionObserver | null>(null); | |
const handleIntersect = useCallback( | |
( | |
entries: IntersectionObserverEntry[], | |
) => { | |
// Check if the sentinel element is intersecting, and if so, call the load function | |
if (entries[0].isIntersecting && hasMore) { | |
load(); | |
} | |
}, | |
[load, hasMore] | |
); | |
useEffect(() => { | |
// Create a new IntersectionObserver when the component mounts | |
observerRef.current = new IntersectionObserver(handleIntersect, { | |
root: null, | |
rootMargin: "0px", | |
threshold: 1.0, | |
}); | |
// Attach the observer to the sentinel element | |
if (sentinelRef.current) { | |
observerRef.current.observe(sentinelRef.current); | |
} | |
// Clean up the observer when the component unmounts | |
return () => { | |
if (observerRef.current) { | |
observerRef.current.disconnect(); | |
} | |
}; | |
}, [load, handleIntersect]); | |
useEffect(() => { | |
// When the hasMore prop changes, disconnect the previous observer and reattach it to the new sentinel element | |
if (observerRef.current && sentinelRef.current) { | |
observerRef.current.disconnect(); | |
observerRef.current.observe(sentinelRef.current); | |
} | |
}, [hasMore]); | |
return ( | |
<div> | |
{children} | |
<div ref={sentinelRef}>{hasMore && loader}</div> | |
{!hasMore && endMessage} | |
</div> | |
); | |
}; | |
export default InfiniteScroll; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment