Asked By: Anonymous
In my application, I want to initialize 3 Vuex modules before the rest of the application starts. However, no matter what I try, the code in the Vue instance life cycle hook in which I perform the initialize, moves on before the 3 modules have completed their initialization.
I have added a promise around the code in the Vuex actions that do the initializing, so that I can (a)wait on those in the calling life cycle hook, but it doesn’t work.
I have looked at sample Vuex code that uses Axios, and I have to make my code similar to that, but without success.
I tried init call in the “beforeCreate” life cycle hook with “Promise.all(…)”, but that still did not fix it.
The code of my main Vue instance looks like this:
new Vue({
router,
store,
async beforeCreate() {
await this.$store.dispatch('init')
},
render: h => h(App)
}).$mount('#app')
The Vuex store consists of 3 modules, all of which have a ‘init’ action. The code of action in all 3 modules is the same. Where ever there is “XXX” in the code below, will be a slightly different call for each module;
init: ({commit, dispatch}) => {
return new Promise((resolve, reject) => {
console.log('Start of init of XXX');
Axios.get(`api/xxx`).then(response => {
return response.data;
}, error => {
console.log('An error occured: ', error);
reject(error);
}).then(data => {
const result = [];
for (let key in data) {
result.push(data[key]);
}
console.log('The API call resulted in ' + result.length + ' lines of code');
resolve(result);
commit('ADD_XXX', result);
})
})
}
What I expect is that the “beforeCreate” code waits with moving on until the 3 init action calls have been fully completed (i.e. until all promises have been fulfilled).
What I see, is that the actions are started (I see the “Start of init…” log in the console). But then I see that code in the mounted() function of one of the applications components is started to execute, which it should not, as it will not work correctly if the store has not been fully initialized.
Solution
Answered By: Anonymous
You can’t pause beforeCreate
by making it async
. It might appear to be ‘paused’ internally when you hit the await
but from an external perspective it just returns a promise. Vue doesn’t take any notice of the return value so the promise will be ignored and the life-cycle will continue uninterrupted. What you can do is add some state into your data
and manipulate that to achieve the desired effect:
new Vue({
router,
store,
data () {
return {
ready: false
}
},
async beforeCreate() {
await this.$store.dispatch('init')
this.ready = true
},
render (h) {
if (this.ready) {
return h(App)
}
}
}).$mount('#app')
Incidentally, you shouldn’t need to create a new promise in init
, you can just return the chained promise created by axios.
Update:
Here’s another way, just holding back on calling mount
.
new Vue({
router,
store,
async beforeCreate() {
await this.$store.dispatch('init')
this.$mount('#app')
},
render: h => h(App)
})