Intersection Observer In React
Creating Dynamic UI Effects with Intersection Observer and React
Table of contents
What does Intersection Observer API do?
Intersection Observer enables us to detect the visibility of an element.
What it internally does is it lets us pass a function as its parameter. This function in turn is a callback function. This callback function is called whenever the given condition of visibility of an element is fulfilled.
For example, If we need to render "IN VIEWPORT" in the navbar when the div with className "box" is in the viewport and "NOT IN VIEWPORT" when it is not. We make a ref instance using the useRef hook and pass that ref in the "box" div.
function App() {
const containerRef = useRef(null);
return (
<div className="box" ref={containerRef}>
Observe Me
</div>
);
}
Then, we create a useEffect and attach the Intersection Observer to the containerRef.
function App() {
const containerRef = useRef(null);
const [isVisible, setIsVisible] = useState(false);
const callbackFunction = (entries) => {
const [entry] = entries;
setIsVisible(entry.isIntersecting);
};
// We will talk about options in-depth very soon in this article
const options = {
root: null,
rootMargin: "0px",
threshold: 1.0
};
useEffect(() => {
const observer = new IntersectionObserver(callbackFunction, options);
if (containerRef.current) observer.observe(containerRef.current);
return () => {
if (containerRef.current) observer.unobserve(containerRef.current);
};
}, [containerRef, options]);
Whenever the "box" is inside viewport, we will set the "isVisible" state to true. This will also make the "isVisible" state false when the "box" leaves the viewport. It will conditionally render the title in the navbar div.
We will also make a basic change in the return of this "app" function for layout. The end result code will look something similar to the below code.
import React, { useRef, useEffect, useState } from "react";
function App() {
const containerRef = useRef(null);
const [isVisible, setIsVisible] = useState(false);
const callbackFunction = (entries) => {
const [entry] = entries;
setIsVisible(entry.isIntersecting);
};
const options = {
root: null,
rootMargin: "0px",
threshold: 1.0
};
useEffect(() => {
const observer = new IntersectionObserver(callbackFunction, options);
if (containerRef.current) observer.observe(containerRef.current);
return () => {
if (containerRef.current) observer.unobserve(containerRef.current);
};
}, [containerRef, options]);
return (
<div className="app">
<div className="isVisible">
{isVisible ? "IN VIEWPORT" : "NOT IN VIEWPORT"}
</div>
<div className="section"></div>
<div className="box" ref={containerRef}>
Observe me
</div>
</div>
);
}
export default App;
Some Common Usecases Of Intersection Observer API are:-
Lazy Loading of Images
Infinite Scrolls
Reveal Animations
Steps to use Intersection Observer
Create an observer with some "options".
Then you ask the observer to observe a component.
When the desired intersection occurs, the callback function given by us is called.
The Options:-
root - The outer rectangle or rectangle inside which you want to observe for an intersection.
rootMargin - The margin around the root element.
threshold - either single no. or array of nos. which tells at what percentage of the target element's visibility should the callback function be executed. (The element which we are observing is called the target. Ex- Box component).
Key points to remember when using the intersection observer.
The Intersection Observer API is asynchronous. So we need to use the callback function to do something when the intersection happens.
The root element can be decided using css selector.
If we specify
root: document.querySelector('null')
, the current viewport of the user will be the root element.