Skip to content

Instantly share code, notes, and snippets.

@scwood
Last active January 30, 2022 20:29
Show Gist options
  • Save scwood/8dbf8cf452ec033b67c87a60896b7ceb to your computer and use it in GitHub Desktop.
Save scwood/8dbf8cf452ec033b67c87a60896b7ceb to your computer and use it in GitHub Desktop.
React hook to track the visibility of an element
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