It is often important to track the user's activity on a website for analytical reasons. Thanks to JavaScript's Intersection Observer API, detecting the visibility of an element in a website has now become easier.
The Intersection Observer API observes an element and detects when it is visible in the viewport, and in turn, triggers a callback function.
In this article, we will walk through an example of how we can create a useIntersection Custom Hook in React. This hook detects when a particular section of a page is viewed by the user for more than 3 seconds.
Check out the demo below.
Basic Usage
We will first create an isVisible
state inside the useIntersection
hook and set its initial value to false.
useIntersection.js
const useIntersection = () => {
const [isVisible, setIsVisible] = useState(false);
return isVisible;
}
To use the Intersection Observer API, we need to create an observer in the useEffect
hook.
useIntersection.js
import { useState, useEffect } from "react";
const useIntersection = (element, rootMargin = "0px") => {
const [isVisible, setIsVisible] = useState(false);
useEffect(() => {
let currentElement;
const observer = new IntersectionObserver(
([{ isIntersecting }]) => {}, { rootMargin });
if (element?.current) {
currentElement = element.current;
observer.observe(currentElement);
}
return () => {
observer.unobserve(currentElement);
};
}, [element, rootMargin]);
return isVisible;
}
export default useIntersection;
The Intersection API takes two parameters:
- The callback function
- Observer's options
The observer watches the target element and the callback function has an isIntersecting
boolean value. The rootMargin
is one of the options of the Intersection API. The rootMargin
parameter is the minimum number of pixels which when visible in the viewport would change the isIntersecting
value.
In this scenario, since the rootMargin
is 0px
, the isIntersecting
value changes to true as soon as the currentElement
is visible in the viewport.
To capture the isIntersecting
state after 3 seconds, we need to create a timer and set the isVisible
state to the isIntersecting
value as shown below.
useIntersection.js
const useIntersection = (element, delay = 3000, rootMargin = "0px") => {
const [isVisible, setIsVisible] = useState(false);
useEffect(() => {
let currentElement, timer;
const observer = new IntersectionObserver(
[{ isIntersecting }]) => {
if (timer && !isIntersecting) clearTimeout(timer);
timer = setTimeout(() => {
setIsVisible(isIntersecting);
}, delay);
},
{ rootMargin });
if (element?.current) {
currentElement = element.current;
observer.observe(currentElement);
}
return () => {
clearTimeout(timer);
observer.unobserve(currentElement);
};
}, [element, rootMargin]);
return isVisible;
}
export default useIntersection;
Calling the useIntersection Hook
The useIntersection
hook has been used in App.js as shown below.
App.js
import { useEffect, useRef } from "react";
import useIntersection from "./customHook/useIntersection";
export default function App() {
const sectionFourRef = useRef(null);
const sectionIsInViewport = useIntersection(sectionFourRef);
useEffect(() => {
if (sectionIsInViewport && sectionFourRef?.current) {
const sectionText = sectionFourRef.current.textContent;
window.alert(`${sectionText} is visible in the viewport!`);
}
}, [sectionIsInViewport]);
return (
<>
<header>Header</header>
<section>Section-1</section>
<section>Section-2</section>
<section>Section-3</section>
<section ref={sectionFourRef}>Section-4</section>
<section>Section-5</section>
<footer>Footer</footer>
</>
);}
In the above code, we created a ref called sectionFourRef
and passed it to the useIntersection
custom hook. The hook watches for the Section-4 element in the page and displays an alert box every time the user views the section for more than 3 seconds.
Top comments (0)