Skip to content

Instantly share code, notes, and snippets.

@HoraceShmorace
Last active July 9, 2024 15:25
Show Gist options
  • Save HoraceShmorace/99480fa5cda245ceeedcf3c5e6218646 to your computer and use it in GitHub Desktop.
Save HoraceShmorace/99480fa5cda245ceeedcf3c5e6218646 to your computer and use it in GitHub Desktop.
Custom hook for setting up an intersection observer on a DOM element to determine its visibility relative to a specified viewport or the default viewport. Implements the native `IntersectionObserver` JavaScript class.
/**
* Custom hook for setting up an intersection observer on a DOM element to determine its visibility relative to a specified viewport or the default viewport. Implements the native `IntersectionObserver` JavaScript class.
*
* @param {React.RefObject} ref - Required. The React ref object pointing
* @param {Object} options - The options for setting up the observer.
to the DOM element to observe.
* @param {Element|null} [options.root=null] - The element that is used as the viewport for checking visibility of the target. Defaults to the browser viewport if not specified.
* @param {string} [options.rootMargin="0px"] - The margin around the viewport or "root". Can have values similar to the CSS margin property, e.g. "10px 20px 30px 40px" (top, right, bottom, left).
* @param {number} [options.threshold=0.5] - A single number or array of numbers indicating at what percentage of the target's visibility the observer's callback should execute. Ranges from 0 to 1.
* @returns {boolean} True if a current interection is present for the element for which the the React ref was pssed. False otherwise.
* @example
* function MyComponent() {
* const ref = useRef(null);
* const { isIntersecting } = useIntersectionObserver({ ref });
*
* return <div ref={ref}>isIntersecting: { isIntersecting? 'Y' : 'N' }!</div>;
* }
*
* @example https://codepen.io/HoraceShmorace/pen/GRLBBmM
* @see Complete example at https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver
*/
const useIntersectionObserver = (ref, options = {
root: null,
rootMargin: "0px",
threshold: 0.5
}) => {
if (!ref) throw "You must pass a reference {React.RefObject}.";
const [entry, setEntry] = useState(false);
const handleIntersection = (entries) => {
const [entry = {}] = entries;
setEntry(entry);
};
useEffect(() => {
const rootElement = ref.current;
const observer = new IntersectionObserver(handleIntersection, options);
if (rootElement) {
observer.observe(rootElement);
}
return () => {
if (rootElement) observer.unobserve(rootElement);
observer.disconnect();
};
}, [ref.current]);
return entry;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment