56 lines
1.3 KiB
TypeScript
56 lines
1.3 KiB
TypeScript
'use client';
|
|
|
|
import { useEffect, useRef, useState } from 'react';
|
|
|
|
type UseIntersectionObserverOptions = {
|
|
threshold?: number;
|
|
rootMargin?: string;
|
|
onIntersect: () => void;
|
|
};
|
|
|
|
type UseIntersectionObserverReturn = {
|
|
ref: React.RefObject<HTMLDivElement | null>;
|
|
isIntersecting: boolean;
|
|
};
|
|
|
|
export const useIntersectionObserver = ({
|
|
onIntersect,
|
|
threshold = 0.1,
|
|
rootMargin = '0px',
|
|
}: UseIntersectionObserverOptions): UseIntersectionObserverReturn => {
|
|
const ref = useRef<HTMLDivElement>(null);
|
|
const [isIntersecting, setIsIntersecting] = useState(false);
|
|
const hasIntersectedRef = useRef(false);
|
|
|
|
useEffect(() => {
|
|
const element = ref.current;
|
|
if (!element) return;
|
|
|
|
const observer = new IntersectionObserver(
|
|
(entries) => {
|
|
entries.forEach((entry) => {
|
|
const intersecting = entry.isIntersecting;
|
|
setIsIntersecting(intersecting);
|
|
|
|
if (intersecting && !hasIntersectedRef.current) {
|
|
hasIntersectedRef.current = true;
|
|
onIntersect();
|
|
}
|
|
});
|
|
},
|
|
{
|
|
threshold,
|
|
rootMargin,
|
|
}
|
|
);
|
|
|
|
observer.observe(element);
|
|
|
|
return () => {
|
|
observer.disconnect();
|
|
};
|
|
}, [onIntersect, threshold, rootMargin]);
|
|
|
|
return { ref, isIntersecting };
|
|
};
|