Create a performant virtual scrolling list in Vue.js 

4 min read 1165

Create Performant Virtualized Lists Vue

Rendering items on the DOM individually can cause a significant performance lag for users, especially when they’re scrolling through large lists. To make scrolling more efficient, we should use a virtual scroll list, which increases page load speed and prevents the web application from stuttering.

A virtual scroll list is similar to a standard scroll list, however, only the data in the user’s current view is rendered at any moment. As a user scrolls down a page, new items are rendered as older items are removed.

In this article, we’ll explore vue-virtual-scroll-list, an amazing library for creating virtual scroll lists in Vue.js. Let’s get started!

Rendering content in vue-virtual-scroll-list

The vue-virtual-scroll-list library has two primary methods for rendering a webpage’s content into a list, item mode and v-for mode.

item mode is ideal for rendering static content. Once content is appended on the DOM, item mode frees up the memory that was being used. If you change the data, you’ll need to call forceRender() and start the process again.

To render dynamic content, the better choice is v-for mode. In v-for mode, the data provided to the list is referenced inside the memory. Therefore, when the data changes, list items are re-rendered and the context is maintained.

Let’s take a closer look at the vue-virtual-scroll-list library by comparing the performance of item mode with and without using a virtual scroll list.

First, we’ll set up a new Vue.js project and install vue-virtual-scroll-list. Then, we’ll create a list using randomly generated data. Finally, we’ll render our list with and without virtual scrolling, comparing the performance of each.

Setting up a Vue.js project

First, make sure you have Vue.js installed on your machine. Create a new Vue.js project with the following command:

vue create virtual-scroll-demo

Once the project is set up, install the vue-virtual-scroll-list library:

We made a custom demo for .
No really. Click here to check it out.

npm install vue-virtual-scroll-list --save

Now, our project has the following structure:

New Vue Project Structure

Generating a list

Now that we have the base for our project set up, let’s get started on the foundation for creating both of our lists.

Navigate to your /src folder and create a file called data.js. Let’s add the following simple function that generates random data to data.js:

let idCounter = 0;

export function getData(count) {
  const data = [];
  for (let index = 0; index < count; index++) {
    data.push({
      id: String(idCounter++),
      text: Math.random()
        .toString(16)
        .substr(10),
    });
  }
  return data;
}

Next, we’ll create a new file called Item.vue, which is the item component that we’ll render. In Item.vue, we’ll include the following code block, which creates a template and styling for our list, as well as props that retrieve and display the data generated above:

<template>
  <div class="item">
    <div class="id">{{ source.id }} - {{ source.text }}</div>
  </div>
</template>

<script>
export default {
  name: 'item',
  props: {
    source: {
      type: Object,
      default() {
        return {}
      }
    }
  }
}
</script>

<style scoped>
.item {
  display: flex;
  flex-direction: column;
  border-bottom: 1px solid lightgrey;
  padding: 1em;
}
</style>

Rendering a list without virtual scroll

Now that we have a list created, let’s render the list items on our DOM without using the vue-virtual-scroll-list. Add the following code to App.vue:

<template>
  <div id="app">
    <div class="wrapper">
    <div class="list">
      <p  v-for="item in items" :key="item">
    {{item}}
  </p>
      </div>

    </div>
  </div>
</template>

<script>
import Item from './Item'
import { getData } from './data'

export default {
  name: 'App',
  data() {
    return {
      item: Item,
      items: getData(100000)
    }
  }
}
</script>

<style>
#app {
  text-align: center;
  color: #2c3e50;
  margin-top: 1em;
  padding: 1em;
}
.list {
  border: 2px solid red;
  border-radius: 3px;
}
</style>

In the code block above, we rendered 100,000 items into our DOM. Let’s see how our list will perform with this much data and no virtual scroll. Start the project with the following npm command:

npm run serve

We’ll get the following output:

List Item Render Standard Scroll

When we check the inspect element in the browser, we’ll see that all of the HTML elements have been appended to the browser DOM, as seen in the image below:

Browser Inspect Element HTML Output

Appending elements in the browser DOM will increase the DOM’s size. Therefore, the browser will require more time to append each item to the DOM, potentially causing a significant performance lag. Let’s look closely at the amount of time it took the browser to append our list to the DOM:

Standard List Component Browser Dom Load Time

The event DOMContentLoaded fired after 22 seconds, meaning the browser tab required 22 seconds to load before displaying the final rendered list. Similarly, as seen in the image below, rendering our list consumed 128 MB of memory:

Standard List Component Browser Dom Memory Consumption

Rendering a list with virtual scroll

Now, let’s try rendering our list using a virtual scroll. Import the vue-virtual-scroll-list package in main.js:

import Vue from "vue";
import App from "./App.vue";

Vue.config.productionTip = false;

import VirtualList from "vue-virtual-scroll-list";

Vue.component("virtual-list", VirtualList);
new Vue({
  render: (h) => h(App),
}).$mount("#app");

Next, we’ll render the data for the items inside the virtual-list component. Let’s change our App.js file to look like the following code block:

<template>
  <div id="app">
    <div class="wrapper">


       <virtual-list
        class="list"
        style="height: 360px; overflow-y: auto;"
        :data-key="'id'"
        :data-sources="items"
        :data-component="item"
        :estimate-size="50"
      />
    </div>
  </div>
</template>

<script>
import Item from './Item'
import { getData } from './data'

export default {
  name: 'App',
  data() {
    return {
      item: Item,
      items: getData(100000)
    }
  }
}
</script>

<style>
#app {
  text-align: center;
  color: #2c3e50;
  margin-top: 1em;
  padding: 1em;
}
.list {
  border: 2px solid red;
  border-radius: 3px;
}
</style>

Note that the data props are required for the virtual list to render the items. Running the code block above will give us the following output:

Virtual Scroll Component Output

We can see in the image below that only a few items are rendered at one time. When the user scrolls down, newer items are rendered:

Virtual Scroll Item Render Order

Now, our DOM tree is much smaller than before! When we render our virtual scroll list, DOMContentLoaded will fire much faster than before!

Virtual Scroll List Dom Render Time

As seen in the image above, the event fired in only 563 milliseconds. Similarly, our operation consumed only 79 MB of memory, which is much less than when we didn’t use a virtual scroll.

Virtual Scroll List DOM Memory Consumption

Conclusion

Now you know how to create a virtual scrolling list in Vue.js using the vue-virtual-scroll-list library!

In this tutorial, we created a static list that uses randomly generated data, then implemented it in our Vue.js application, comparing its performance with and without using a virtual scroll.

Virtual scrolling lists are highly performant, especially when you have a large list of items on your webpage. Using a virtual scroll list can increase the page load speed and improve the user experience overall!

 

Experience your Vue apps exactly how a user does

Debugging Vue.js applications can be difficult, especially when there are dozens, if not hundreds of mutations during a user session. If you’re interested in monitoring and tracking Vue mutations for all of your users in production, try LogRocket. https://logrocket.com/signup/

LogRocket is like a DVR for web apps, recording literally everything that happens in your Vue apps including network requests, JavaScript errors, performance problems, and much more. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred.

The LogRocket Vuex plugin logs Vuex mutations to the LogRocket console, giving you context around what led to an error, and what state the application was in when an issue occurred.

Modernize how you debug your Vue apps - .

Testing accessibility with Storybook

One big challenge when building a component library is prioritizing accessibility. Accessibility is usually seen as one of those “nice-to-have” features, and unfortunately, we’re...
Laura Carballo
4 min read

Leave a Reply