如何在加载某些异步数据(在 Vuex 存储中)之前防止任何路由?

How to prevent any routing before some async data (in Vuex store) has loaded?

在我的应用程序中,我需要在路由开始之前将一些数据加载到 VueX 存储中(例如用户会话)。

竞争条件的示例如下:

// In routes definition
{
  name: 'login',
  path: '/login',
  component: Login,
  meta: {
    goToIndexIf: () => store.getters['auth/loggedIn']
  }
}

在这种情况下,路由守卫可能会在从服务器接收到用户之前执行。

使用条件渲染没有帮助,因为路由守卫在渲染模板中使用或不使用 <router-view v-if="storeReady"> 执行。

如何让我的所有路由都等待一些异步数据?

解决方法很简单。在商店的相关部分添加 init 或等效的 Vuex action
它应该 return 您的应用程序 绝对需要的所有数据请求的 Promise *:

init ({ dispatch }) {       // Could also be async and use await instead of return
  return Promise.all([
    dispatch('getUserSession'), // Using another <b>action</b>
    dispatch('auth/init'),      // In another module
    fetch('tehKittenz')         // With the native <b>fetch</b> API
    // ...
  ])
}

以上代码可以使用任何 return 是 Promise

然后只需使用 beforeEach 在您的路由器中创建一个 global navigation guard
这个守卫将等待 dispatch 对商店产生的承诺。

// In your router initialization code
const storeInit = store.dispatch('init')

// Before <b>all other beforeEach</b>
router.beforeEach((to, from, next) => {
  storeInit.then(next)
    .catch(e => {
      // Handle error
    })
})

这样,如果路由发生在商店完全加载之前,路由器将简单地等待。
如果之后发生路由,promise 将已经处于 fulfilled 状态并且路由将继续。

不要忘记使用 conditional rendering 这样的东西,以免在路由等待数据时显示空白屏幕。


*:只要正在获取数据,这将阻止所有路由和导航。当心。

我所做的和对我来说很好的工作是将我的 Vue 实例 (new Vue({... })) 包装在 .then()“Promise”中。如果一切正常,这个 promise 将解决(null)并在发生错误时解决错误,这样我就可以根据错误

有条件地渲染 vue 实例

here i call my async function and wait until it loads the store and then initialize my app

my async function that uses the token to get me the data

这样做将使处理获取的商店数据的路由守卫正常工作

希望对您有所帮助,如果我的英语不好,请见谅:)

自从第一次提出这个问题后,vue-router (v3.5.1) 已经公开了 check for the initial navigation 仅在第一条路线上执行这样的操作和 运行 的能力。

比较 fromVueRouter.START_LOCATION

import VueRouter from 'vue-router'

const router = new VueRouter({
  // ...
})

router.beforeEach((to, from, next) => {
  if (from === VueRouter.START_LOCATION) {
    // initial navigation, handle Vuex initialization/hydration.
    initalizeOrWait().then((isLoggedIn) => {
      // handle navigation or pass to guard how it fits your needs here etc.
      next();
    });
  } else {
    next();
  }
})