I'm trying to track element visibility with React/Hooks and the Intersection Observer API. However, I can't figure out how to set up observation with "useEffect". Does anybody have any idea how could I do that? Mine solution does not work...
function MainProvider({ children }) {
const [targetToObserve, setTargetToObserve] = useState([]);
window.addEventListener("load", () => {
const findTarget = document.querySelector("#thirdItem");
setTargetToObserve([findTarget]);
});
useEffect(() => {
const observer = new IntersectionObserver(
([entry]) => {
if (entry.intersectionRatio === 0.1) {
console.log("It works!");
}
},
{
root: null,
rootMargin: "0px",
threshold: 0.1
}
);
if (targetToObserve.current) {
observer.observe(targetToObserve.current);
}
}, []);
return (
<main>
<div className="Section-item" id="firstItem"></div>
<div className="Section-item" id="secondItem"></div>
<div className="Section-item" id="thirdItem"></div>
</main>
);
}
The IntersectionObserver interface of the Intersection Observer API provides a way to asynchronously observe changes in the intersection of a target element with an ancestor element or with a top-level document's viewport. The ancestor element or viewport is referred to as the root.
Thresholds. Rather than reporting every infinitesimal change in how much a target element is visible, the Intersection Observer API uses thresholds. When you create an observer, you can provide one or more numeric values representing percentages of the target element which are visible.
Need to use React.useRef() instead of addEventListener('load', function() ), since eventListener will run before something will appear on your screen.
import React, { useRef, useEffect } from 'react'
function MainProvider({ children }) {
const ref = useRef();
useEffect(() => {
const observer = new IntersectionObserver(
([entry]) => {
console.log(entry);
if (entry.isIntersecting) {
//do your actions here
console.log('It works!')
}
},
{
root: null,
rootMargin: "0px",
threshold: 0.1
}
);
if (ref.current) {
observer.observe(ref.current);
}
}, [ref]);
return (
<main>
<div className="Section-item" id="firstItem"></div>
<div className="Section-item" ref={ref} id="secondItem"></div>
<div className="Section-item" id="thirdItem"></div>
</main>
);
}
Here is a reusable hook that is using ref
and useEffect
cleanup function to prevent memory leakage when mounting / unmounting large amount of components
function useOnScreen(ref) {
const [isIntersecting, setIntersecting] = useState(false)
const observer = new IntersectionObserver(
([entry]) => setIntersecting(entry.isIntersecting)
)
useEffect(() => {
observer.observe(ref.current)
return () => {
observer.disconnect()
}
}, [])
return isIntersecting
}
function DumbComponent() {
const ref = useRef()
const onScreen = useOnScreen(ref)
return <div ref={ref}>{onScreen && "I'm on screen!"}</div>
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With