Vue / Router: How do I correctly fetch data before rendering page content?

What is happening there, is that you already calling next and that's why the route enters immediately.

Where you are calling next ?

beforeRouteEnter (to, from, next) {
    next(vm => {  // <= HERE you execute next
        vm.fetchPageData(next);
    });
},

And the above code will execute vm.fetchPageData when the component is already rendered.

So even if you don't call next on the fetchPageData the route will enter.


By assuming that you want to enter the view after certain data is fetched by BE you can use beforeEnter on the router config:

const router = new VueRouter({
  routes: [
    {
      path: '/foo',
      component: Foo,
      beforeEnter: (to, from, next) => {
        axios.get('api/...')
          .then(response => {
             store.commit('mutation', response)
             next()
          })
          .catch(e => {
            alert('Something went wrong')
            next(false)
          })
      }
    }
  ]
})

Another solution would be to allow the route to enter but show a loader while data is being fetched: Checkout this answer


You are right, calling next() second time is incorrect. Your first call to next() tells Router "go on, you can proceed with changing active component (create/mount/render) and when the component is created, call my callback (passed as an argument to next())

You can follow guidance in Data fetching - fetching before navigation Docs ie. fetching data first and call next() after but that requires to extract fetch logic from the component itself.

Generally I find easier to write all component in the way assuming data are not here on 1st render and are coming later when all async calls resolve...

UPDATE Nuxt async data fetching options

As you are using Nuxt.js you have some other options how to use async data:

  1. nuxtServerInit - useful to fill client-side Vuex store with data from server side
  2. fetch method - The fetch method is used to fill the store before rendering the page. It's like the asyncData method except it doesn't set the component data and allows you to put the data into the store. Returning Promise from fetch method will make Nuxt wait for promise to resolve before it renders the component...
  3. asyncData method can be used to to fetch data and put it inside component's data. Returning Promise from asyncData method will make Nuxt wait for promise to resolve before it renders the component...
export default {
  async fetch({store, $axios}) {
    const result = await $axios.$get('/api/v2/inventory/3906');
    store.commit('property/setProperty', result[0]);
  }
}