Learn how to create a powerful useInView hook in React using the Intersection Observer API. Elevate your development skills as we guide you through step-by-step instructions to create a custom useInView hook. Enhance user experience, optimize performance, and effortlessly track element visibility in your React projects.
Follow this video to step-by-step instructions
useInView.ts
import { useRef, useState, useEffect, RefObject } from 'react';
interface IOptions {
root?: Element | null | undefined;
rootMargin?: string,
thresholds?: ReadonlyArray<number>
}
type useInViewType = {
inView: boolean
ref: RefObject<T> | null,
observe: (element: RefObject<T>, callback: (entries: IntersectionObserverEntry[]) => void) => IntersectionObserver | null,
unObserve: (observer: IntersectionObserver) => void
}
const useInView = (options: IOptions): useInViewType => {
const [inView, setInView] = useState(false)
const containerRef = useRef(null)
const callback = (entries: IntersectionObserverEntry[]) => {
const [entry] = entries
setInView(entry.isIntersecting)
}
useEffect(() => {
const _observer = new IntersectionObserver(callback, options)
if (containerRef.current) _observer.observe(containerRef.current)
return () => {
if (containerRef.current) _observer.unobserve(containerRef.current)
}
}, [containerRef, options])
// For Manual observers
const observe = (element: RefObject<T>, callback: (entries: IntersectionObserverEntry[]) => void) => {
const _observer = new IntersectionObserver(callback, options)
containerRef.current = element.current
return _observer
}
const unObserve = (observer: IntersectionObserver) => {
if (containerRef.current) observer.unobserve(containerRef.current)
}
return {
inView,
ref: containerRef,
observe,
unObserve
}
}
export default useInView;
Usage:
function App() {
const [data, setData] = useState<any[]>([])
const [page, setPage] = useState(1)
const { ref, inView } = useInView({ thresholds: [2] })
useEffect(() => {
setData([...new Array(5 * page)])
}, [page])
useEffect(() => {
if (inView) setPage(prev => prev + 1)
}, [inView])
return (
<div className={styles.mainContainer}>
{data.map((row: any, index: number) => {
return <Card key={`card-${index.toString()}`} index={index} />
})}
<button ref={ref} className={styles.loadMore}>Load More</button>
</div>
)
}
Working Demo:
Top comments (0)