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

Kyl*_*yll 8 javascript race-condition vue.js vue-router vuex

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

竞争条件的一个例子如下:

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

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

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

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

Kyl*_*yll 9

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

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

上面的代码可以使用任何返回Promise.

然后,只需创建一个全球导航卫使用你的路由器beforeEach
这个守卫将等待由 a 生成的dispatch对商店的承诺。

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

// Before all other beforeEach
router.beforeEach((to, from, next) => {
  storeInit.then(next)
    .catch(e => {
      // Handle error
    })
})
Run Code Online (Sandbox Code Playgroud)

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

不要忘记使用条件渲染之类的东西,以免在路由等待数据时显示空白屏幕。


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


小智 5

自从第一次提出这个问题以来,vue-router(v3.5.1)已经公开了检查初始导航以执行此类操作并仅在第一条路线上运行的功能。

相比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();
  }
})
Run Code Online (Sandbox Code Playgroud)