Infinite Scrolling in Vue using the Vue Intersection Observer API
Tags: javascript, vue, tutorial
Published: 2021-09-15 20:50:12

_by author [Uma Victor](https://blog.openreplay.com/authors/uma-victor)_

In a Vue web application, sometimes we fetch so much data from an API we cannot display on our site at once, because of performance issues, instead, we want to display them in chunks. 

One of the most challenging parts of building a frontend app is implementing the ability to control the events and properties of the application. Trying to implement an infinite scrolling feature incorrectly can affect the performance of the app.
Many developers run into issues when trying to implement infinite scroll with third-party libraries, but some of the libraries or methods used are typically not the best option in terms of performance.

The Vue Intersection Observer API is an alternative that lets us observe changes in an intersection of a target element and an ancestor element. It also has a callback function that will fire if the element gets into the viewport.

## How the Vue Intersection Observer API works

[This API](https://www.npmjs.com/package/vue-intersection-observer) is a component-based library built on top of the native Javascript API. It does a lot of useful things that were previously only possible through scrolling events. Instead of just firing off a bunch of events, it will wait for the target to appear before firing an event.
These events can be used to watch for things that enter or leave the viewport. They can also change how much of an item has been displayed on the page it is.

## Setting up our Project

We won’t be using Vue CLI to spin off this project, instead we will host our project in this [codesandbox](https://codesandbox.io/s/dazzling-shaw-3ytjt?file=/src/App.vue). The code is available there and can be forked and even improved upon. 

```javascript
//html
<template>
  <div class="p-3">
    <div class="mx-auto max-w-screen-lg">
      <h1>All Comments</h1>
      <div class="py-4">
        <div v-for="(quote, i) in quotes" :key="quote._id">
          <div :class="`contain-quote ${i % 2 == 0 ? 'bg-gray-100' : ''}`">
            <p class="my-5 text-lg text-center text-gray-500">
              <span>"{{ quote.quoteText }}"</span><br />
              <span class="text-gray-400">- {{ quote.quoteAuthor }}</span>
            </p>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
import axios from "axios";
export default {
  name: "all",
  data() {
    return {
      quotes: [],
    };
  },
  methods: {
    async getQuotes() {
      try {
        const response = await axios.get(
          `https://quote-garden.herokuapp.com/api/v3/quotes?page=${this.page}`
        );
        // JSON responses are automatically parsed.
        const data = await response.data;
        this.quotes = data.data
        console.log(this.quotes);
      } catch (error) {
        console.log(error);
      }
    },
  },
  mounted() {
    this.getQuotes();
  },
};
</script>
```


This is the starting code we need to implement the infinite scroll feature in Vue. Let me do a rundown of what is going on in the code above. We will be using an open-source API in this project. Our API returns an array of quotes., and we can see in our data object, we have our comments array defined so we can store the array of objects we get from our API.  

We have an async method called `getQuotes` that fetches quotes from our API and fills up our Quotes array with the quotes. The `getQuotes` function runs each time our page is mounted because we have called it in our `mounted` hook.
In our template, we loop over the array of objects and display the Quote and the author of the quote accordingly.


## Vue Observability Package

The `vue-observe-visibility` is a package that uses the [Intersection Observer API](http://caniuse.com/#feat=intersectionobserver) to make things like infinite scrolling on a website easier to implement. We need to install it in our project to use it by running

```
npm install --save vue-observe-visibility
```

Now we have it installed, we want to set it up. To do this, we go to our `main.js` file in the vue project and import the package, also asking Vue to acknowledge and use the third party library

```javascript
import VueObserveVisibility from "vue-observe-visibility";
Vue.use(VueObserveVisibility);
```


We now have access to the `v-observe-visibility` directive in our application.


## Open Source Session Replay
Debugging a web application in production may be challenging and time-consuming. [OpenReplay](https://github.com/openreplay/openreplay) is an Open-source alternative to FullStory, LogRocket and Hotjar. It allows you to monitor and replay everything your users do and shows how your app behaves for every issue. 
It’s like having your browser’s inspector open while looking over your user’s shoulder.
OpenReplay is the only open-source alternative currently available.

![OpenReplay](https://raw.githubusercontent.com/openreplay/openreplay/main/static/replayer.png)

Happy debugging, for modern frontend teams - [Start monitoring your web app for free](https://github.com/openreplay/openreplay).

## Add Infinite Scroll to the Page

In our template, under the things we are rendering which are our quotes, we create an empty `div`.  In the `div`, we will set the directive `v-observe-visibility` to call a method called `handleInfinityScroll`. 


```html
<div v-observe-visibility="handleInfinityScroll">
```

There are a lot of things you can do to customize this plugin, you can go ahead and check the [documentation](https://github.com/Akryum/vue-observe-visibility).
In our scripts, we want to check if the `handleInfinityScroll` function is called first of all, so we can log something into the console.

```javascript
methods: {
      handleInfinityScroll() {
      console.log("fetch more stuff");
    },
  },
```


Now if we reload our app and scroll to the bottom, we can see the `fetch more stuff` logging to the console each time. The `*handleInfinityScroll*` is being called frequently and only calling it when the bottom of the page is visible is a reasonable thing to do. 

```javascript
handleInfinityScroll(isVisible) {
  if (!isVisible) {
    return;
  }
  console.log("hehe");
},
```



So to fix this, we pass on an argument `isVisible` and check for visibility of the page bottom by using an `if` statement to decide if the page bottom is visible or not.
We will return from the function if the page bottom is not visible, and if it is visible, we call the `getQuotes()` function again.

## Infinite Scrolling by Pages

```javascript
<script>
import axios from "axios";
export default {
  name: "all",
  data() {
    return {
      quotes: [],
      page: 1,
      totalpage: 7268,
    };
  },
  methods: {
    async getQuotes() {
      try {
        const response = await axios.get(
          `https://quote-garden.herokuapp.com/api/v3/quotes?page=${this.page}`
        );
        // JSON responses are automatically parsed.
        const data = await response.data;
        this.quotes.push(...data.data);
        console.log(this.quotes);
      } catch (error) {
        console.log(error);
      }
    },
    handleInfinityScroll(isVisible) {
      if (!isVisible) {
        return;
      }
      if (this.page >= this.totalpage) {
        return;
      }
      this.page++;
      this.getQuotes();
      console.log("hehe");
    },
  },
  mounted() {
    this.getQuotes();
  },
};
</script>
```
    

There is quite a lot going on above, let’s break it down. We can see that we set a `page` state in our data object, also there is a total page state set to `7268`. The page we are currently on is dynamically connected to our API call, so if we make our initial request to the API `https://quote-garden.herokuapp.com/api/v3/quotes?page=${this.page}`, to get the quotes, we will be fetching data for page `1`.
In the `handleInfinityScroll` scroll method, after we check if the page bottom is visible, we want to increment the page count and call the `getQuote()` function again which fetches a new set of quote data for page `2`.

```javascript
this.page++;
this.getQuotes();
```



We noticed something earlier, which is where we set the quotes array equal to our array directly

```javascript
this.quotes = data.data
```

Now we push the array of objects into our `quotes` array in our data each time the `getQuotes()` function re-runs. We also spread the objects so each time the `getQuotes()` function is called, we just keep adding the new objects to the ones we already have in our quotes array.

## Knowing when to stop

Since the page ends at `7268` as specified by our API, we notice that if we reach the end of the page, our API keeps making requests to pages that do not really exist. We can improve on this by perfoming another check in our `handleInfinityScroll` function. What we want to do is check if our current page is greater than or equal to the total number of pages and if it returns `true`, we return out of the function.

```javascript
if (this.page >= this.totalpage) {
    return;
  }
```

## Conclusion

Yayy!. We have finally come to the end of this tutorial. We learned how to use the Vue observer API package in implementing infinite scroll. I hope you do more wonderful things with the Vue observer API. Feel free to reach out to me on [Twitter](https://twitter.com/umavictor_).