# Infinite Scroll in React - Without External Libraries

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.

```javascript
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

```javascript
//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.

```javascript
//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/](https://effortless-granita-f1a33d.netlify.app/)

And you can get the code here: [https://github.com/theshubhagrwl/infinite-scroll-react-window](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!
