import { useEffect, useState } from 'react'; const ObserverParams: IntersectionObserverInit = { threshold: 0.1, }; /** * useHasIntersected. * Use this custom hook to detect when an element has became visible inside the viewport. This hook checks only if the intersection happend. * Once the intersection has happened the hook will not return false even if the element gets out of the viewport. * * @param {object} params * @param {object} [params.elRef] - node object that contains a react reference to the element that needs to be observed. * @param {string} [params.loading = 'eager'] - string that contains the type of loading. * @param elRef.loading * @usage `const [hasIntersected] = useHasIntersected({imageRef,loading});` */ export const useHasIntersected = ({ elRef, loading = 'eager', }: { elRef: React.RefObject; loading?: 'eager' | 'lazy'; }) => { const [hasIntersected, setHasIntersected] = useState(false); const { current } = elRef || {}; const isValidReference = () => { return elRef && current; }; const handleOnIntersect: IntersectionObserverCallback = (entries, observer) => { entries.forEach((entry) => { if (entry.isIntersecting) { setHasIntersected(true); if (current) { observer.unobserve(current); } } }); }; useEffect(() => { let observer: IntersectionObserver | undefined; let didCancel = false; // Check if window is defined for SSR and Old browsers fallback if (typeof window === 'undefined' || !window.IntersectionObserver || !isValidReference()) { setHasIntersected(true); } else if (current && !didCancel) { observer = new IntersectionObserver(handleOnIntersect, ObserverParams); observer.observe(current); } return () => { didCancel = true; if (observer && current) { observer.unobserve(current); } }; }, [elRef]); if (loading === 'eager') { return [false]; } return [hasIntersected]; };