Reputation:
I use vuex and have a store module to load for example users lists in my app (for selects etc.). It uses ajax and after load list, doesn't do this anymore (if list is present in vuex store). I do this in main app layout, but in async way i.e. without await, without blocking. Ajax request is in vuex dispatch action. "loadUsers".
Some pages (for example /users-list) needs data from this users lists and also called "loadUsers", but in other way - with await, after load, render page to avoid any issues.
Everything is ok, if user opens main page (/) and then go to users list (/users-lists), but if we try to open users list directly, as first page in browser, "loadUsers" is called twice - one time from main layout, second from users-list page.
The question is, how can handle this, load list only once? It will be called in layout, so, second call from users-list page should also wait for result. But how to do this? Code are in different files, and I'm not sure, how to do this. Save promise from ajax call also on vuex, and return it to other calls?
In timeline it looks now:
Upvotes: 1
Views: 574
Reputation:
I tested this today with saving promise in vuex and it works perfectly. Example:
async loadUsers ({ state, commit }) {
if (state.users.length) {
return state.users
}
if (state.fetchPromise) {
return state.fetchPromise
}
let promise = fetch(usersUrl).then((response) => {
commit('SET_USERS', response.data)
})
commit('SET_PROMISE', promise);
return promise
}
Now it's possible to use it in many completely separate components without calling request many times and without breaking anything. Example it to run it on main layout:
created () {
this.$store.dispatch('users/loadUsers')
}
It's called without await, so asynchronous and will NOT block rendering page. But on users-list page this list is REQUIRED, so here we can put:
async beforeMount () {
await this.$store.dispatch('users/loadUsers')
}
Result: loadUsers will be dispatched twice - one time from layout, second from users-list, but it will send request only ONCE. Also, users-lists will correctly wait for response, instead of trying render something without data.
Upvotes: 2
Reputation: 11979
I had to deal with something similar and this is how I solved it:
In your main file, define a new state variable, called pending. And you would use it in your loadUsers action this way:
async loadUsers ({ state, commit }) {
if (state.users.length) {
return state.users;
}
if (state.isPending) {
return;
}
commit('SET_PENDING_STATE', true);
const users = await fetch(usersUrl);
commit('SET_PENDING_STATE', false);
commit('SET_USERS', users);
}
Upvotes: 0