Hello Everyone!
Today, I am sharing an easy and quick way to implement infinite scrolling in your websites using the Intersection Observer API. Let's understand what is Intersection Observer API and what does it comprise.
What is Intersection Observer API?
Here's what MDN docs say,
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.
In simple terms, Intersection Observer API makes it easy to detect when an element enters the viewport and take an action when it appears. There is no more need to bind events & keep performance optimization in mind while calculating the existence of an element in the viewport. Intersection Observer API removes all the overhead and delivers great performance out of the box.
What are the possible applications of the Intersection Observer API?
The Intersection Observer API can be used in a variety of different applications such as:
Lazy-loading of images or other content as a page is scrolled.
Implementing "infinite scrolling" websites
Reporting of visibility of advertisements in order to calculate ad revenues.
Telling the browser to only execute the code once the element is visible at the viewport
What are the key concepts of the Intersection Observer API?
IntersectionObserver
Interface
This interface is used to create a new observer which will keep track of changes in the intersection of a target element.
let options = {
root: document.querySelector('#scrollArea'),
rootMargin: '0px',
threshold: 1.0
}
let observer = new IntersectionObserver(callback, options)
The above code snippet creates a new intersection observer using the IntersectionObserver
constructor. The first argument is a callback
function that is called when our target element enters the viewport. We'll look more into the callback function later with the example. The second argument is the options
object which helps you control the situations under which the callback function is called. It contains the following fields:
root
: The element that is set as a viewport for checking the visibility of the target element which must be a parent (ancestor) of the target element.rootMargin
: This is equivalent to the CSS margin property which is defined on the root element.threshold
: A number or an array of numbers indicating at what percentage of the target's visibility the callback function should be invoked.
How to implement Infinite Scrolling using the Intersection Observer API?
Let's start implementing Infinite Scrolling of images using Intersection Observer API. I am going to implement it using react & javascript.
App.js
Component
We first define an imageList variable that contains a list of image URLs to show images on the browser. Then define a div
which will be the parent element in this case. The Image
component renders each image by taking the src
prop from the parent. Also, it takes key to differentiate each child image component and the setImageList
function which we will see in a while.
Here's our App.js file
export default function App() {
const root = useRef(null);
const [imageList, setImageList] = useState(getImageList(true));
return (
<div ref={root} className="App">
<h1>Lazy loading</h1>
{imageList.map((url) => {
return <Image key={url} src={url} setImageList={setImageList} />;
})}
</div>
);
}
Image
Component
This is where we employ the Intersection Observer API to lazily load images and make them scroll infinitely. Here useRef
is used to point to the current img
element defined at the last. Similarly, the observer variable is used to point to the observer returned by the Intersection Observer API. Inside the useEffect()
we call the IntersectionObserver
constructor and pass a callback function. This function receives a entries
array which contains a list of IntersectionObserverEntry
objects. It has intersectionRatio
property which determines the visibility of currentElement
in the viewport. The value 0.5 suggests that when the visibility of currentElement
is at least 50%, then display this image & load the next images in imageList
array.
The root option is provided with the value of rootElement i.e. parent. Threshold receives an array of values. Threshold value is defined as:
A threshold of 1.0 means that when 100% of the target is visible within the element specified by the root option, the callback is invoked.
Here's our Image.js
file
export const Image = ({ src, rootElement, setImageList }) => {
const ref = useRef(null);
const observer = useRef(null);
useEffect(() => {
const currentElement = ref.current;
if (currentElement) {
observer.current = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.intersectionRatio > 0.5) {
ref.current.src = src;
observer.current.unobserve(currentElement);
setImageList((imageList) => [...imageList, ...getImageList()]);
}
});
},
{
root: rootElement,
threshold: [0, 0.5, 1]
}
);
observer.current.observe(currentElement);
}
return () => {
observer.current.unobserve(currentElement);
};
}, [ref]);
return <img ref={ref} width="200px" height="200px" alt="" />;
};
Final Output
Conclusion
There are infinite possibilities using the Intersection Observer API. You can greatly improve the performance & overall user experience of your web apps by reducing load time. You can lazy load images, implement infinite scrolling, link-prefetching and so on.
Browser support for the Intersection Observer API is strong & a majority of modern browsers are supporting it. You can try out this API in your web apps and you'll see the difference it makes.
Thank you guys for reading up till here, I hope you enjoyed and learnt something new! You can connect with me on Twitter, LinkedIn & GitHub.
Happy Coding!
References: