Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to access async store data in vue-router for usage in beforeEnter hook?

How is it possible to access store data in beforeEnter which is retrieved asynchronously via the store action?

import store from './vuex/store';  store.dispatch('initApp'); // in here, async data will be fetched and assigned to the store's state  // following is an excerpt of the routes object: {   path: '/example',   component: Example,   beforeEnter: (to, from, next) =>   {     if (store.state.asyncData) {       // the above state is not available here, since it       // it is resolved asynchronously in the store action     }   } } 

This is especially important on the first page load or after a page reload, when the init data is being fetched and the router needs to wait for that data to either allow the user to access that page or not.

Is it possible for the router to "wait" for the data to be fetched? Or what's the best way to handle navigation guard in combination with async vuex store data?

(oh and pre-populating "asyncData" can't be the solution, since the beforeEnter hook needs to make its decision on real data from the database, not default data)

like image 719
santacruz Avatar asked Mar 03 '17 13:03

santacruz


People also ask

What is router-link in Vue JS?

May 13, 2020. The router-link component creates an <a> tag that's configured to work correctly with Vue router.


2 Answers

You can do it by returning a promise from vuex action, as it is explained here and call the dispatch from within the beforeEnter itself.

Code should look like following:

import store from './vuex/store';   // following is an excerpt of the routes object: {   path: '/example',   component: Example,   beforeEnter: (to, from, next) =>   {     store.dispatch('initApp').then(response => {         // the above state is not available here, since it         // it is resolved asynchronously in the store action     }, error => {         // handle error here     })            } } 
like image 136
Saurabh Avatar answered Oct 04 '22 20:10

Saurabh


Do you really need to fetch the data asynchronously from the server before every route change, or do you simply need to persist some data from the store so that they do not "disappear" when the page is reloaded or when user uses a direct link?

If the latter is the case, you can persist the auth data (e.g. JWT token) in localStorage/cookie and then simply pull them from the storage during initialization (and commit them to store) - this should be a synchronous action.

You can also persist the whole state of the store by using vuex-persistedstate so that it doesn't disappear on reload and doesn't need to be hydrated.

If you need to fetch some data asynchronously once before first load or page reload, you can dispatch a store action and initialize the Vue instance in the then() callback - but this might depend on your implementation. Something like this (in main.js):

import Vue from 'vue'; import VueRouter from 'vue-router'; import { sync } from 'vuex-router-sync';  // contains VueRouter instance and route definitions import router from 'src/router/router'; // contains Vuex.Store instance. I guess this is './vuex/store' in your example? import store from 'src/store/store';  // sync the router with vuex store using vuex-router-sync Vue.use(VueRouter); sync(store, router);  // dispatch init action, doing asynchronous stuff, commiting to store store.dispatch('initApp').then(() => {     // create the main Vue instance and mount it     new Vue({         router,         store                }).$mount('#app'); }); 
like image 29
Arx Avatar answered Oct 04 '22 18:10

Arx