w3resource
Vue Tutorial

Dynamic & Async Components

keep-alive with Dynamic Components

Previously, we had used the is attribute to enable switch between components in a tabbed interface as shown below:

<component v-bind:is="currentTabComponent"></component>

However, when we are switching between these components, we sometimes want to maintain their state or for performance reasons avoid re-rendering.

Take for instance you have an application that has a posts tab and an archive tab, when we select a tab and switch over to the Archive tab, the post will be deselected, because Vue will create a new instance of currentTabComponent.

Recreating dynamic components is usually a useful behavior, but in the case above, we would really like those tab components to be cached when they are created for the first time.

We achieve this by wrapping our dynamic component with a <keep-alive> element:

<keep-alive>
  <component v-bind:is="currentTabComponent"></component>
</keep-alive>

Async Components

When building a large application, there may be a need to divide the app into smaller chunks and only a component when it is need. Vue makes this easier by allowing us to define our component as a factory function that asynchronously resolves our component definition. This factory function will only be triggered when the component needs to be rendered and the result will be cached for future re-render:

Vue.component('async-example', function (resolve, reject) {
  setTimeout(function () {
    // this will Pass the component definition to the resolve callback
    resolve({
      template: '<div>I am async!</div>'
    })
  }, 1000)
})

From the code snippet above, the factory receives a resolve callback, which should be called when our component definition is retrieved from the server.

A recommended alternative to using the setTimeout is using async components and Webpack's code-splitting feature:

Vue.component('async-webpack-example', function (resolve) {
// This special require syntax below will instruct Webpack to
  // automatically split your built code into bundles that
  // are loaded from an Ajax request.
    require(['./my-async-component'], resolve)
})

Additionally, we can return a Promise in the factory function , thus with ES6 and Webpack 2 we can do the following:

Vue.component(
  'async-webpack-example',
  // The `import` function below returns a Promise.
  () => import('./my-async-component')
)```
When registering locally, we can also directly provide a function that returns a Promise:
```new Vue({
  // ...
  components: {
    'my-component': () => import('./my-async-component')
  }
})

If you rather prefer to use Browserify and also would like to make use of async components, note that the creator of Browserify has made it clear that this is not something that Browserify will ever support.

Handling Loading State

The async component factory can return an object as well with the following format:

const AsyncComponent = () => ({
  // The component to be load (should be a Promise)
  component: import('./MyComponent.vue'),
  // this is a component to use while the async component is loading
  loading: LoadingComponent,
  // A component to use if the load fails
  error: ErrorComponent,
  // this will Delay before showing the loading component. The Default is: 200ms.
  delay: 200,
  // The error component will then be displayed if a timeout is
  // provided and is exceeded. Default: Infinity.
  timeout: 3000
})