DEV Community

Cover image for Infinite Scroll Using Intersection Observer API ๐Ÿ˜‰
Deepak Yadav
Deepak Yadav

Posted on

Infinite Scroll Using Intersection Observer API ๐Ÿ˜‰

Intersection Observer API helps to asynchronously observe changes in the intersection of a target element and perform some actions based on the intersection.
This can be used to determine if an element is visible within the viewport or if it has been scrolled out of view, allowing for efficient implementation of things like lazy loading of images, infinite scrolling, and element tracking for analytics.


One common use case for the Intersection Observer API is the lazy loading of images. Lazy loading is a technique used to delay the loading of images on a web page until the user actually needs them. This can greatly improve the performance of a web page, especially on mobile devices or slow internet connections. By using the Intersection Observer API to determine when an image is about to enter the viewport, developers can load the image just before it is needed, reducing the amount of data that needs to be loaded upfront and improving the overall loading time of the web page.

Infinite Scrolling

Another use case for the Intersection Observer API is infinite scrolling. Infinite scrolling is a technique used to load additional content as the user scrolls down the web page. By using the Intersection Observer API to determine when the user has reached the bottom of the page, developers can load additional content seamlessly, providing a more fluid and seamless experience for the user.


We are going to cover the implementation of infinite scrolling of products using Intersection Observer API in this article ๐Ÿซก.

One of the great things about this API is that it allows for the creation of custom hooks that can be easily reused across multiple components.

Let's do this

So, first, let's start by creating a new function called useIntersectionObserver:

Creating CustomHook



function useIntersectionObserver(options) { 

const { 
root = null, 
target, 
onIntersect, 
threshold = 0.9, 
rootMargin = "0px", 
enabled = true, 
} = options; 

useEffect(() => {  
// Intersection Observer logic here 
 }, [target.current,enabled]);  

}



Enter fullscreen mode Exit fullscreen mode

This function takes in an options object (which is destructured in this example) that can be used to customize the behaviour of the Intersection Observer. The useEffect hook is used to run the Intersection Observer logic when the element is intersected or enables is set as true.

Next, we can use the IntersectionObserver constructor to create a new observer inside the UseEffect we defined:

Intersection Observer Object



const observer = new IntersectionObserver((entries) =>  
entries.forEach((entry) => entry.isIntersecting && onIntersect()),  
   {
    root: root && root.current, 
    rootMargin, 
    threshold, 
   } 
); 

const el = target && target.current; 
if (!el) { 
    return; 
} 
observer.observe(el); 
return () => { 
    observer.unobserve(el); 
};



Enter fullscreen mode Exit fullscreen mode

This observer takes in two arguments: a callback function that will be called whenever an intersection event occurs, and an options object that can be used to customize the behaviour of the observer. In this case, we are using the callback function to check the isIntersecting property and call the onIntersect function.

Make sure to unobserve the Intersection Observer as unobserving unnecessary elements can help to avoid unnecessary use of resources such as memory and CPU power, this can be especially important in situations where an observer is monitoring a large number of elements, or when the web page is running on a device with limited resources.

Finally, we can use the current property of the useRef hook to attach the observer to the target element in our component where we need to implement infinite scrolling:

The useRef hook creates a reference to the target element, and the useEffect hook is used to attach the observer to the element when it is intersected.

Now that we have our custom hook, we can use it to determine when an element is visible within the viewport:

Calling Intersection CustoomHook



function MyComponent() {
  const loadMoreButtonRef = useRef();
  useIntersectionObserver({
    target: loadMoreProductsRef,
    onIntersect: fetchNextPage,
    enabled: hasNextPage
  });
  return (
    <div>
      {page.results.products.map((product, index) => {
        return (
          <div key={product.product_id}>
            {/* Insert Product Card Component */}
          </div>
        );
      })}
      <div ref={loadMoreProductsRef}>
        {/* Last Product Reached */}
      </div>
    </div>
  );
}



Enter fullscreen mode Exit fullscreen mode

In conclusion, creating a custom hook for the Intersection Observer API can greatly simplify the process of monitoring the visibility of elements on a web page.

And we are almost there in implementing the infinite scroll. Create a useEffect to call the update the next page state and make the API call.

API call



const [currentPage, setCurrentPage] = useState(1); 
const [hasNextPage, setHasNextPage] = useState(false);
const fetchNextPage = () => { 
  setCurrentPage((prev) => prev + 1); 
} 
useEffect(() => { 
  (async () => { 
    try { 
      await fetchproducts(currentPage); 
      //Make api call with the updated page count and set hasNextPage
    } catch (error) { 
      // Handle the error 
    } 
  })() 
},[currentPage])



Enter fullscreen mode Exit fullscreen mode

And it's done, and infinite scrolling is up and running ! ๐Ÿ”ฅ

Note: Giving heads-up for a stale state, closures situation which may eat up some of your hair. Make sure to handle those with a coffee๐Ÿง‹.

Conclusion

This sums up the implementation of Intersection Observer API for infinite scrolling. Using the intersection observer can be helpful and has quite a few use cases and also it helps to avoid using some different libraries.

Hit ๐Ÿ‘๐Ÿผ if you find this helpful, and share your thoughts below :)

Connect with me ๐Ÿ™‹๐Ÿปโ€โ™‚๏ธ on LinkedIn ~ Twitter

Top comments (0)