Skip to content

How to prevent any routing before some async data (in Vuex store) has loaded?

In my application I need some data to be loaded inside the VueX store before routing starts (for example user sessions).

An example of a race condition would be the following:

// In routes definition
  name: 'login',
  path: '/login',
  component: Login,
  meta: {
    goToIndexIf: () => store.getters['auth/loggedIn']

In this situation the route guard might be executed before the user had been received from the server.

Using conditional rendering did not help as the route guards are executed with or without a <router-view v-if="storeReady"> within the rendered template.

How can I make all my routing wait on some asynchronous data?


The solution is simple. Add an init or equivalent Vuex action to the relevant parts of your store.
It should return a Promise of all the requests for data that your application absolutely needs*:

init ({ dispatch }) {       // Could also be async and use await instead of return
  return Promise.all([
    dispatch('getUserSession'), // Using another action
    dispatch('auth/init'),      // In another module
    fetch('tehKittenz')         // With the native fetch API
    // ...

The above code can use anything that returns a Promise.

Then just create a global navigation guard in your router using beforeEach.
This guard will wait on the promise generated by a dispatch to the store.

// In your router initialization code
const storeInit = store.dispatch('init')
// Before all other beforeEach
router.beforeEach((to, from, next) => {
    .catch(e => {
      // Handle error

This way, if routing happens before the store is fully loaded the router will simply wait.
If routing happens after, the promise will already be in a fulfilled state and routing will proceed.

Don’t forget to use something like conditional rendering so as not to display a blank screen while routing is waiting on the data.

*: This will prevent all routing and navigation as long as the data is being fetched. Be careful.