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

核能气质少年 提交于 2019-12-03 02:23:49
Saurabh

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
    })         
  }
}

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');
});

I've solved this issue by using store.watch() for no initial value and return the latest value when already initialized.

Here is my sample code

async function redirectIfNotAuth (to, from, next) {
  const user = await getUserState()
  if (user === null) {
    next({ name: 'auth' })
  } else {
    next()
  }
}

function getUserState () {
  return new Promise((resolve, reject) => {
    if (store.state.user === undefined) {
      const unwatch = store.watch(
        () => store.state.user,
        (value) => {
          unwatch()
          resolve(value)
        }
      )
    } else {
      resolve(store.state.user)
    }
  })
}


/* STORE */
const store = new Vuex.Store({
  state: {
    user: undefined
  }
})

/* ROUTER */
new Router({
  routes: [
    {
      path: '',
      name: 'home',
      component: Home,
      beforeEnter: redirectIfNotAuth
    },
    {
      path: '/signin',
      name: 'auth',
      component: Auth,
    }
  ]
})
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!