如何在vue-router中访问异步存储数据以便在beforeEnter hook中使用?

时间:2017-03-03 13:02:32

标签: javascript vue.js vuex vue-router

如何通过商店操作以异步方式检索beforeEnter中的商店数据?

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

这对于第一页加载或页面重新加载,获取init数据以及路由器需要等待该数据以允许用户访问该页面时,这一点尤为重要。

路由器是否可以等待"要获取的数据? 或者什么是与异步vuex商店数据结合处理导航防护的最佳方式?

(哦,预先填充" asyncData"不能成为解决方案,因为beforeEnter挂钩需要根据数据库做出真实数据,而不是默认数据)

3 个答案:

答案 0 :(得分:11)

您可以通过从vuex操作返回承诺来执行此操作,因为它已解释为here并从beforeEnter内部调用调度。

代码应如下所示:

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

答案 1 :(得分:7)

您是否真的需要在每次路由更改之前从服务器异步获取数据,或者您是否只需要保留商店中的某些数据,以便在重新加载页面或用户使用时不会“消失”直接链接?

如果是后一种情况,您可以将身份验证数据(例如JWT令牌)保存在localStorage / cookie 中,然后在初始化期间将它们从存储中拉出(并将它们提交到存储) - 这应该是一个同步动作。

您还可以使用vuex-persistedstate 保留商店的整个州,以便在重新加载时不会消失,也不需要保持水分。

如果您需要在首次加载或页面重新加载之前异步获取某些数据,您可以调度存储操作并在then()回调中初始化Vue实例 - 但这可能取决于你的实施。这样的事情(在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');
});

答案 2 :(得分:5)

我通过使用store.watch()没有初始值来解决这个问题,并在初始化时返回最新值。

这是我的示例代码

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