Infinite Scroll in React - Without External Libraries

Photo by Max Duzij on Unsplash

Infinite Scroll in React - Without External Libraries

Add infinite scrolling to your react app without any dependencies

ยท

4 min read

Infinite Scroll is an effect we put on websites to create a seamless user experience. This effect is no magic, it is just some clever use of JavaScript to give the website a better overall experience.

This technique is used on many websites, especially those with a feed, e.g. YouTube.

So how does this thing works?

Let's discuss the basic idea of Infinite Scrolling.

In an Infinite Scroll, the user is shown a single page with limited results. When the user reaches the end of those results, more content is loaded, and this goes on.

So what actually happens here?

For an Infinite Scroll, we prefer an API that has pagination enabled. So first, we simply request the first page from the API. Now when the user reaches the end of the page, a new API call is made with the next page number.

As you might have noticed from the above paragraph, we make the API call when we reach the end of the page. There are two ways to detect the end of the page. Either the page is fully scrolled, or the last element is fully visible on the screen. In this article, we are going to learn how to exactly do this.

We will discuss two methods of implementing Infinite Scroll

Prerequisites

  • Knowledge of React Hook: useState, useRef, useEffect

  • A basic react application setup

Implementation - #1

In this method, we will use the different values of windows that are provided by the browser.

We need to attach a scroll event listener to the window. This will be done inside useEffect because the listener needs to be attached as soon as the component is mounted.

useEffect(() => {
    window.addEventListener("scroll",handleInfiniteScroll);
    return () => window.removeEventListener("scroll", handleInfiniteScroll);
},[])

When the component is loaded, we have attached a Scroll Event listener to the page which will run handleInfiniteScroll the method. Then we remove that event listener in the cleanup method of useEffect.

Try to remove the cleanup method (return) in the useEffect and run the code. Observer carefully how the requests are being made then.

Let's define handleInfiniteScroll method

//states
const [page, setPage] = useState(1);
const [loading, setLoading] = useState(true);

//method
const handleInfiniteScroll = async () => {
    try {
      if (
        window.innerHeight + window.document.documentElement.scrollTop + 1 >=
        window.document.documentElement.scrollHeight
      ) {
        setLoading(true);
        setPage((prev) => prev + 1);
      }
    } catch (error) {
      console.error(error);
    }
  };

We have declared two states here, page keeps track of the page number because our API supports pagination so we need to pass a page number to it.

In the handleInfiniteScroll method, we are checking for the condition that, the sum of window.innerHeight and window.document.documentElement.scrollTop + an additional number of pixels is greater than equal to window.document.scrollHeight.

window.innerHeight: Returns the interior height of the window in pixels
window.document.documentElement.scrollTop : Returns the number of pixels that are scrolled vertically
window.document.documentElement.scrollHeight: Returns the total height of content (which is yet not visible on the screen)

So when innerHeight and scrollTop are added together they will always result in scrollHeight. You can verify this by doing a console log of these values and checking them manually.

This method will make changes to the state page. So we will add an useEffect which will call our API.

//state
const [card, setCard] = useState([])

//method
const getCardData = async () => {
    const res = await fetch(
      `https://jsonplaceholder.typicode.com/posts?_limit=9&_page=${page}`
    );
    const data = await res.json();
    //solved: the first page is repeated twice
    if (page !== 1) {
      setCard((prev) => [...prev, ...data]);
    } else {
      setCard([...data]);
    }
    setLoading(false);
  };

//useEffect
useEffect(() => {
  getCardData();
}, [page]);

This piece of code is really simple. All we have done here is called the API and stored the data in setCard() (probably not a good name ๐Ÿ˜…)

Now that we have all the main code setup we can simply pass our data which is in card to a component that will render the items.

And THAT'S IT!!

You get an infinite scroll there.

Here is a live demo of the app that I created: https://effortless-granita-f1a33d.netlify.app/

And you can get the code here: https://github.com/theshubhagrwl/infinite-scroll-react-window

Implementation - #2

In this... well let's continue this is next article.

To give you a hint, in the second approach we will use the IntersectionObserver API

Good Day!

Did you find this article valuable?

Support Shubh Agrawal by becoming a sponsor. Any amount is appreciated!