DEV Community

Cover image for Infinite Scrolling in Vue using the Vue Intersection Observer API
OpenReplay Tech Blog
OpenReplay Tech Blog

Posted on • Updated on • Originally published at blog.openreplay.com

Infinite Scrolling in Vue using the Vue Intersection Observer API

by author 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 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. The code is available there and can be forked and even improved upon.

//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>
Enter fullscreen mode Exit fullscreen mode

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 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
Enter fullscreen mode Exit fullscreen mode

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

import VueObserveVisibility from "vue-observe-visibility";
Vue.use(VueObserveVisibility);
Enter fullscreen mode Exit fullscreen mode

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

Happy debugging, for modern frontend teams - Start monitoring your web app for free.

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.

<div v-observe-visibility="handleInfinityScroll">
Enter fullscreen mode Exit fullscreen mode

There are a lot of things you can do to customize this plugin, you can go ahead and check the documentation.
In our scripts, we want to check if the handleInfinityScroll function is called first of all, so we can log something into the console.

methods: {
      handleInfinityScroll() {
      console.log("fetch more stuff");
    },
  },
Enter fullscreen mode Exit fullscreen mode

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.

handleInfinityScroll(isVisible) {
  if (!isVisible) {
    return;
  }
  console.log("hehe");
},
Enter fullscreen mode Exit fullscreen mode

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

<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>
Enter fullscreen mode Exit fullscreen mode

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.

this.page++;
this.getQuotes();
Enter fullscreen mode Exit fullscreen mode

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

this.quotes = data.data
Enter fullscreen mode Exit fullscreen mode

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.

if (this.page >= this.totalpage) {
    return;
  }
Enter fullscreen mode Exit fullscreen mode

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.

Discussion (0)