How async components can optimize performance in Vue apps
Tags: vue, javascript
Published: 2019-09-04 14:46:29

---
title: How async components can optimize performance in Vue apps
published: true
tags: vue, javascript
canonical_url: https://blog.logrocket.com/how-async-components-can-optimize-performance-in-vue-apps/
cover_image: https://thepracticaldev.s3.amazonaws.com/i/p117pe94dvz18x3z0rc5.png
---
**Written by [Raphael Ugwu](https://blog.logrocket.com/author/raphaelugwu/)**✏️

It’s important to take component structure into account when using JavaScript frameworks to create large scale applications.

By considering component structure, you can avoid loading every single component at runtime and slowing your application. You can also keep from returning unnecessary data to users or creating an overall poor user experience as you build your application.

Frameworks such as React and Angular use `React.lazy()` and routing models, respectively, to factor in component structure.

In this blog post, we’ll implement a couple of demos to see how Vue uses async components to decrease our application’s loading times by employing lazy loading and code splitting techniques.

[![LogRocket Free Trial Banner](https://i0.wp.com/blog.logrocket.com/wp-content/uploads/2017/03/f760c-1gpjapknnuyhu8esa3z0jga.png?resize=1200%2C280&ssl=1)](https://logrocket.com/signup/)

### Creating a component in Vue

To understand how this works, let’s begin by creating a basic component.

Navigate to your terminal, install Vue’s CLI, and create a project:

```jsx
npm install -g vue/cli
vue create book-project
#choose the default setting when prompted
```

In our new project folder, let’s replace the contents of the default files, which include `HelloWorld.vue` and `App.vue`. We’ll start by creating a book donation page. Rename `HelloWorld.vue` to `Book.vue` and replace its content with the following:

```jsx
<!--Book.vue-->
<template>
  <h1>Donate Books</h1>
</template>
```

Then replace the contents of `App.vue` with this:

```jsx
<!--App.vue-->
<template>
  <div>
    <book></book>
  </div>
</template>

<script>
  Import Book from "./components/Book"
  export default {
    components: {
      Book
    }
  }
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>
```

In the code block above, you’ll notice that the `Book` component was statically imported. This means the `Book` component loads every time we load our application.

Next, run `npm run serve` in your terminal, navigate to `localhost:8080`, and look at your basic component:

![An example of how to use async components to optimize performance in Vue.](https://i0.wp.com/blog.logrocket.com/wp-content/uploads/2019/08/Donate-Books-async-components.png?resize=730%2C456&ssl=1)

For now, loading the `Book` component every time you load the app may not seem like a significant performance issue. However, as your app gets larger, loading every single component at runtime will become burdensome.

Your users won’t interact with every piece of functionality in your application, so it makes sense to only serve them what they need. The question is, how can you load only what your users need?

This is where lazy loading and code splitting techniques come into play. Lazy loading delays the initial load of a component, preventing resources such as images from loading until users navigate to where they are located on the page.

Code splitting is a feature originally provided by [webpack](https://webpack.js.org/). Webpack lets you split your code into various bundles that can be used only when needed.

Vue performs code splitting via a feature known as dynamic imports.

This import uses webpack — or any module bundler, such as [Parcel](https://parceljs.org/) — to asynchronously load your component. It is written with a syntax that involves a promise and is wrapped in an arrow function:

```jsx
// dynamic import
import("./components/Book").then(Book => {
  // Insert the Book module here
});
```

Let’s implement this on our `App.vue` component:

```jsx
<template>
  <div>
    <book></book>
  </div>
</template>

<script>
export default {
  components: {
    Book: () => import("./components/Book")
  }
};
</script>
```

In the code sample above, the `import()` function returns the `Book` component, which enables us to load it asynchronously. If we take a look at the `Network` tab in our browser devtools, there’s a file named `0.js` initiated by `App.js`. That file contains our asynchronous component:

![](https://i1.wp.com/blog.logrocket.com/wp-content/uploads/2019/08/app-js-async-component.png?resize=730%2C340&ssl=1)

### Creating a Vue app with async components

Let’s proceed to build a basic book donation app to show how async components can be leveraged. Ultimately, we only want to load our `Donate` component when the user clicks the donate button.

To begin, let’s navigate to the terminal and install `vue-material` in our project folder. We’ll use this to style the app:

```jsx
cd book-project
npm i vue-material
```

We’ll include `vue-material` in the app by importing it in `src/main.js`:

```jsx
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
import VueMaterial from 'vue-material'
import 'vue-material/dist/vue-material.min.css'
import 'vue-material/dist/theme/default.css'
Vue.use(VueMaterial)
new Vue({
  render: h => h(App),
}).$mount('#app')
```

Now, let’s structure the `Book` component we previously created:

```jsx
<!--Book.vue-->
    <template>
     <div id="app">
      <md-card md-with-hover v-for="(book, key) in books" v-bind:key="key">
          <md-ripple>
            <md-card-header>
              <div class="md-title">{{book.name}}</div>
              <div class="md-subhead">{{book.genre}}</div>
            </md-card-header>
            <md-card-actions>
              <md-button type="primary" @click="addBook(key)">Donate to improve {{book.genre}}</md-button>
            </md-card-actions>
          </md-ripple>
        </md-card>
        <div v-if="show">
          <md-card-content>
         <donate v-bind:selectList="selectList"></donate>
          </md-card-content>
    </div>
        <md-button @click="show = true" id="donate">Donate {{selectList.length}} book(s)</md-button>
      </div>  
    </template>
    
    <script>
      export default {
      name: 'RegularButtons',
      methods: {
        addBook (key) {
          if(!this.selectList.includes(key)) {
            this.selectList.push(key);
          }
        }
      },
      components: {
        donate: () => import('./Donate')
      },
      data: () => ({
        books: [
          { name: 'Using Creatine', genre: 'Workouts' },
          { name: 'Learn Parkour', genre: 'Sports' },
          { name: 'Snorkelling', genre: 'Diving' },
        ],
        selectList: [],
        show: false
      })
    }
    </script>
```

In the code block above, a list of books is retrieved from a `Book` array and displayed. If the user clicks the buttons attached to each book, the `addBook()` method pushes the selected book to a `selectList` array and shows the total number of donated books.

There’s also a separate button created solely for the purpose of loading our asynchronous component. It has a parameter `show` set to `true`. This enables the `v-if` statement to display the `donate` component, which contains the number of books selected for donations.

The `donate` component has already been dynamically imported via the `components` property in the `<script>` tag.

Let’s create our `donate` component. In the `src/components` folder, create a new file called `Donate.vue` and input the code sample below:

```jsx
<template>
      <div title="Donate Books" key="donate">
          <p v-for="(x, y) in this.selectList" :key="y">
          Tip: {{books[Number(x)].name}} is about {{books[Number(x)].genre}}
          </p>
      </div>
</template>
<script>
export default {
  props: ['selectList'],
  data: () => ({
    books: [
      { name: 'Using Creatine', genre: 'Workouts' },
      { name: 'Learn Parkour', genre: 'Sports' },
      { name: 'Snorkelling', genre: 'Underwater' },
    ]
  })
}
</script>
```

Navigate to your terminal and run `npm run serve.`

If the app compiles successfully, open `localhost:8080` in your browser. When you click around the app while viewing the network tab in Devtools, the `Donate` component will only load when you click the `Donate` button.

{% youtube Pfam0bIH4To %}

You’ll see in the above video that the `donate` component is represented by `1.js` and doesn’t load in the initial app render.

### Error handling with async components

Async components need to be as simple as possible to load quickly. However, it can be helpful to define loading and error components in our async components to handle loading status and display error messages when needed.

```jsx
In src/components, let's create two components: LoadingState.vue and ErrorState.vue:
```
```jsx
<!--LoadingState.vue-->
    <template>
      <p><em>Loading...</em></p>
    </template>
```
```jsx
<!--ErrorState.vue-->
    <template>
      <p>Could not display books. Kindly check your internet conection.</p>
    </template>
```
Now, in `App.vue`, we’ll import both components and add them to our `Book` component:

```jsx
<!--App.vue-->
<script>
import LoadingState from "./components/LoadingState"
import ErrorState from "./components/ErrorState"
const Book = import("./components/Book")
export default {
  components: {
    Book: () => ({
// Book is our default component
      component: Book,
// LoadingState is the component that is displayed while our default component
// is loading
      loading: LoadingState,
// ErrorState is the component that is displayed should our default component have an // error while loading
      error: ErrorState,
// A delay is set up before the loading component is shown
      delay: 100,
// Should this timeout be reached, the default component is considered to have failed // to load
      timeout: 2000
    })
  }
};
</script>
```

The loading and error states won’t come up unless you have a very slow or faulty internet connection. To test if they work properly, let’s set the `timeout` property to `0` and attempt to load the app:

{% youtube 5IbMToLgouk %}

### Conclusion

Using async components to build large scale apps is key to maintaining optimal performance. Async components not only ensure your retention rate will be higher due to quicker load times, but they can also help you detect errors more efficiently since your components are scoped and passed around as functions. Should you want to take a look at the source code of this demo, you can find it [here](https://github.com/fullstackmafia/vue-async-demo) on GitHub.
* * *
**Editor's note:** Seeing something wrong with this post? You can find the correct version [here](https://blog.logrocket.com/how-async-components-can-optimize-performance-in-vue-apps/).

## Plug: [LogRocket](https://logrocket.com/signup/), a DVR for web apps
 
![LogRocket Dashboard Free Trial Banner](https://i2.wp.com/blog.logrocket.com/wp-content/uploads/2017/03/1d0cd-1s_rmyo6nbrasp-xtvbaxfg.png?resize=1200%2C677&ssl=1)
 
[LogRocket](https://logrocket.com/signup/) is a frontend logging tool that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.
 
In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page apps.
 
[Try it for free](https://logrocket.com/signup/).
* * *
The post [How async components can optimize performance in Vue apps](https://blog.logrocket.com/how-async-components-can-optimize-performance-in-vue-apps/) appeared first on [LogRocket Blog](https://blog.logrocket.com).