2 ways to implement infinite scroll in javascript

Jayesh AdwaniJayesh Adwani
3 min read

Fetching a list from database is always a requirement in almost every app. To cater this, the concept of pagination was introduced. Which helps to fetch data in small chunks to load into UI.

P.S: Fetch data in chunks (via pagenumber)

To achieve this we have 2 options listed below:

  1. Scroller ref

  2. Intersection observer

Let's discuss them for better understanding of when to use what.

For Scroller ref we need to setup scroll bar on the container by giving fix height to the container. So when the scrollbar approaches the end of the scroll we can fetch and load new items to UI.

this.ref = createRef(null)

handleScroll(){
const scrollbar = this.ref.current;
if(scrollbar.scrollHeight - scrollbar.scrollTop <= scrollbar.clientHeight){
// The scrollbar has reached the end
// Your logic to fetch more items goes here
}

<div class="container" ref={this.ref} onScroll={this.handleScroll}>
  // Your list goes here
</div>

// CSS
.container{
height:600px; // adjust as needed
overflow-y: scroll; // can be auto as well
}

Scroller ref works on 3 elements, client height, offset height and scrollHeight. What do you mean????

It can be negative also so === can be replaced by >= to be precise.

Now, getting to know what exactly is meaning of the condition. Demystifing different heights mentioned above.

  1. Scroll height : Total available height to scroll, 600px in our case(container's height)

  2. Client height: The height visible in client's viewport at current scroll position.

  3. Scroll top: is the height of the content that is scrolled up.

So let's take an example with scroll positions,

Client height is 200px (visible content of the container), scroll Height = 600px, and scroll top is 200px

So,

600-200 <= 200, false

600-400 <= 200, true

This condition checks when the user scrolls, if the user has reached the end of scrolling area, then it's time to get more items.

Now, the 2nd elephant in the room,

Intersection Observer is based on logic that when the last-element is visible in viewport call the function to load more items.

The implementation of this logic is quite easy.

#1 Create a custom hook

function useIntersectionObserver(options) { 

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

useEffect(() => {  
 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); 
};
 }, [target.current,enabled]);  

}

#2 Use the intersection observer with ref and options

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>
  );
}

This is reusable code across all components to fetch data when last element is visible in viewport.

Happy learning 🥳 🥳

References:

https://dev.to/thedeepakyadav/infinite-scroll-using-intersection-observer-api-3527

https://javascript.info/size-and-scroll

0
Subscribe to my newsletter

Read articles from Jayesh Adwani directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Jayesh Adwani
Jayesh Adwani