Reputation: 727
I have been struggling to use a vuex.getters
which is computed from a vuex.actions
as an if
statement in router.beforeEach
.
Here is what I am trying to do:
Fetch an array of objects every time user enter the site.
And then use array.find()
to target the one object with the same slug according to the router.params.id
in case user enter the site with direct url.
Redirect route to 404 if router.params.id
doesn't match any slug in the object array.
Here is my approach
const router = new VueRouter(
{
routes: [
{
path: '/list/:id',
name: 'list'
},
{
path: '/edit/:id',
name: 'edit'
},
//other routes
{
path: '/*',
name: '404'
}
]
}
);
router.beforeEach((to, from, next)=>{
if ( !store.state.lists.length ){
// fetch Object Array when user first enter
store.dispatch('fetchLists');
}
if ( to.name === 'list' || to.name === 'edit'){
// limit route only 'list' & 'edit', preventing passing undefined params
store.commit('cloneParams', to);
// determine if currentMonth has a valid slug, if not go to 404
store.getters.currentMonth.slug !== '' ? next() : next('/404');
} else {
next();
}
});
getters: {
currentMonth(state){
var template = {
month: '',
slug: '',
data: []
}
var obj = template;
if ( state.lists.length ) {
obj = state.lists.find(current => current.slug === state.paramsID);
if ( obj === undefined ){
obj = template
}
}
return obj;
},
actions: {
fetchLists({commit}){
axios('/lists').then(
res=>{
commit('storeList', res);
}
)
},
mutations: {
storeList(state, res){
state.lists = res.data;
},
cloneParams(state, to){
state.paramsID = to.params.id;
},
However, I found that the getter currentMonth
does not update after the object array store.state.lists
is fetched and goes to 404. Meanwhile it works perfectly fine after the store.state.lists
is fetched and stored when user goes to next other page of this SPA.
Upvotes: 1
Views: 1215
Reputation: 63099
The route guard isn't waiting for the http request to complete before checking for the api result. Return the promise from fetchLists
:
actions: {
fetchLists({commit}){
return axios('/lists').then(res => { // return the promise
commit('storeList', res);
})
},
And wait for that promise in the navigation guard:
router.beforeEach(async (to, from, next) => { // async keyword
if ( !store.state.lists.length ){
await store.dispatch('fetchLists'); // Waiting for the promise
}
if ( to.name === 'list' || to.name === 'edit'){
// limit route only 'list' & 'edit', preventing passing undefined params
store.commit('cloneParams', to);
// determine if currentMonth has a valid slug, if not go to 404
store.getters.currentMonth.slug !== '' ? next() : next('/404');
} else {
next();
}
});
Upvotes: 1