K1-Aria
K1-Aria

Reputation: 1156

How can I use Vue.js async components?

I'm using Laravel 5.4 and Vue.js 2. I want to load a component as async using a button. My Vue.js components are separate: example.vue and test.vue, and I load them as an HTML tag.

This is my app.js:

import './bootstrap';
import example from './components/Example.vue';

Vue.component('example', example);

const app = new Vue({
    el: '#app'
});

This is the place to show components:

<How can I use Async components?div id="app">
     <example2></example2>
</div>

How can I use async components?


No, I think you don't understand me. It's my component registration:

import './bootstrap';
import example from './components/Example.vue';

Vue.component('example', example);

Vue.component('example2', function (resolve) {

    require(['./components/Example2.vue'],resolve)

})

const app = new Vue({
    el: '#app'
});

And in require, it defaults to resolved (as showing). I don't know how I should pass the resolve and reject keys to this method in my page when I call the component.

Upvotes: 8

Views: 24525

Answers (5)

t_dom93
t_dom93

Reputation: 11486

Vue.js 3 - Breaking Changes

Async components now require the defineAsyncComponent helper method:

// Vue.js 2.x
const asyncPage = () => import('./NextPage.vue')

// Vue.js 3.x
const asyncPage = defineAsyncComponent(() => import('./NextPage.vue'))

Another breaking change is that the component option is renamed to loader when defining additional options:

const asyncPageWithOptions = defineAsyncComponent({
  loader: () => import('./NextPage.vue'),
  delay: 200,
  timeout: 3000,
  error: ErrorComponent,
  loading: LoadingComponent
})

Documentation: Async Components, 3.x Syntax

Upvotes: 1

Sukanta Bala
Sukanta Bala

Reputation: 879

You can use async components in Vue.js 2 with a styling way. Proper using async components can reduce your project loading time.

You can use an async component as like:

import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
export default new Router ({
routes: [
  {
    path: '/',
    name:'LandingPage'
    component: () => import('@/containers/LandingPage.vue')
  },
  {
    path: '/login',
    name:'LoginPage'
    component: () => import('@/containers/LoginPage.vue')
  }
]
})

This structure looks better for component loading inside the template:

new Vue ({
  el: 'app',
    components: {
      AsyncComponent: () => import ('./AsyncComponent.vue')
    }
})

You can check out www.bdtunnel.com for more information.

Upvotes: 10

Gorky
Gorky

Reputation: 1413

According to the documentation on Vue.js, you have been able to define asynchronous components like this since version 2.3:

const AsyncComp = () => ({
  // The component to load. Should be a Promise
  component: import('./MyComp.vue'),
  // A component to use while the async component is loading
  loading: LoadingComp,
  // A component to use if the load fails
  error: ErrorComp,
  // Delay before showing the loading component. Default: 200 ms.
  delay: 200,
  // The error component will be displayed if a timeout is
  // provided and exceeded. Default: Infinity.
  timeout: 3000
})

You can use this in conjunction with built-in components to load your components dynamically.

An updated link to mentioned documentation.

Upvotes: 5

dzwillia
dzwillia

Reputation: 79

One way I've done this sort of thing is to create your example2 component with the following setup:

<template>
  <div>
    <div v-if="inited">
      <div>{{foo}}</div>
      <div>{{bar}}</div>
    </div>
  </div>
</template>

<script>
  export default {
    data() {
      return {
        foo: '',
        bar: '',
        inited: false
      }
    },
    mounted() {
      var me = this
      axios.get('/my/ajax/call').then(function(response) {
        me.foo = response.data.foo
        me.bar = response.data.bar
        me.inited = true
      })
    }
  }
</script>

Basically, anytime the component is mounted, it'll render with empty information until the AJAX call completes and then the reactive data will be updated and Vue will auto-update the reactive data elements. If you have other markup or things in the template you don't want to be visible, you can always create an inited: false data property and set it to true in the AJAX callback and then use either the :v-if="inited" or :v-show="inited" directives on a wrapper div to hide the component's contents until the AJAX call returns.

Upvotes: 1

dzwillia
dzwillia

Reputation: 79

For async components in Vue.js, the resolve argument is the function which is called upon success of the async call, so your require() call needs to be inside the called resolve function. You just need to remove the brackets in your require() call and format that line as follows:

resolve(require('./components/Example2.vue'))

In the example below, we're using a basic setTimeout() to emulate the async call. The resolve function will be called after 5 seconds and will load the Example2 component into the app.

In order to show/hide the Example2 component via a button click, you have to add a reactive data property in the data() function. Then, if you take a look at App.vue's template, we're using the v-if (https://v2.vuejs.org/v2/guide/conditional.html#v-if) directive to add/remove the Example2 component to/from the virtual DOM. You could very easily us the v-show (https://v2.vuejs.org/v2/guide/conditional.html#v-show) directive here as well, although the component would stick around and just be hidden. You can read more about v-if vs v-show here: https://v2.vuejs.org/v2/guide/conditional.html#v-if-vs-v-show. This is a very common paradigm for hiding and showing modals in an app -- here's an example that shows this in action quite well: https://v2.vuejs.org/v2/examples/modal.html

main.js

import Vue from 'vue'
import App from './components/App.vue'

Vue.component('example2', function(resolve, reject) {
  setTimeout(function() {
    resolve(require('./components/Example2.vue'))
  }, 5000)
})

const app = new Vue({
  el: '#app',
  render: h => h(App)
})

Example2.vue

<template>
  <div>
    <div>Hello example 2!</div>
  </div>
</template>      

App.vue

<template>
  <div id="app">
    <button type="button" @click="onButtonClick">Click me to add the example2 component</button>
    <example2 v-if="show_example2"></example2>
  </div>
</template>

<script>
  export default {
    name: 'app',
    data() {
      return {
        show_example2: false
      }
    },
    methods: {
      onButtonClick() {
        this.show_example2: true
      }
    }
  }
</script>

Upvotes: 4

Related Questions