Last active
January 30, 2022 20:29
-
-
Save scwood/8dbf8cf452ec033b67c87a60896b7ceb to your computer and use it in GitHub Desktop.
React hook to track the visibility of an element
This file contains 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 { Dispatch, SetStateAction, useEffect, useState } from "react"; | |
interface VisibilityTrackerResult { | |
/** Ref callback, give this to the element to be observed */ | |
ref: Dispatch<SetStateAction<HTMLElement | null>>; | |
/** Whether or not the observed element is currently visible */ | |
isVisible: boolean; | |
} | |
interface VisibilityTrackerOptions { | |
/** Optional callback called when the observed element becomes visible */ | |
onVisible?: () => void; | |
} | |
/** | |
* Hook used to track the visibility of an element. | |
* @example | |
* function Example() { | |
* const { ref, isVisible } = useVisibilityTracker({ | |
* onVisible: () => | |
* console.log("This is called whenever the element becomes visible"), | |
* }); | |
* | |
* return <div ref={ref}>{isVisible && "Element is visible"}</div>; | |
* } | |
* @param options Optional configuration | |
* @returns VisibilityTrackerResult | |
*/ | |
export function useVisibilityTracker({ | |
onVisible, | |
}: VisibilityTrackerOptions = {}): VisibilityTrackerResult { | |
const [element, setElement] = useState<HTMLElement | null>(null); | |
const [isVisible, setIsVisible] = useState(false); | |
useEffect(() => { | |
const observer = new IntersectionObserver((entries) => { | |
const [{ isIntersecting }] = entries; | |
if (isIntersecting) { | |
setIsVisible(true); | |
if (onVisible) { | |
onVisible(); | |
} | |
} else { | |
setIsVisible(false); | |
} | |
}); | |
if (element) { | |
observer.observe(element); | |
} | |
return () => observer.disconnect(); | |
}, [element, onVisible]); | |
return { ref: setElement, isVisible }; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment