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

san*_*ruz 13 javascript vue.js vue-router vuex

如何在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
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

这在第一页加载或页面重新加载之后,获取初始化数据并且路由器需要等待该数据允许用户访问该页面时尤为重要.

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

(哦和预填充"asyncData"不能解决,因为beforeEnter挂钩需要从数据库做出真实数据的决定,而不是默认数据)

Sau*_*abh 14

您可以通过从vuex操作返回promise来完成此操作,如此处所述,并从内部调用dispatch 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
    })         
  }
}
Run Code Online (Sandbox Code Playgroud)


Arx*_*Arx 9

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

如果是后者,您可以将auth数据(例如JWT令牌)保存在localStorage/cookie中,然后在初始化期间将它们从存储中拉出(并将它们提交到存储) - 这应该是同步操作.

您还可以使用vuex-persistedstate保持商店的整个状态,这样它在重新加载时不会消失,也不需要保持水分.

如果您需要在首次加载或页面重新加载之前异步获取一些数据,则可以调度存储操作并在then()回调中初始化Vue实例- 但这可能取决于您的实现.像这样(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');
});
Run Code Online (Sandbox Code Playgroud)


小智 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,
    }
  ]
})
Run Code Online (Sandbox Code Playgroud)