【问题标题】:Execute Vuex action before initial routing在初始路由之前执行 Vuex 动作
【发布时间】:2021-04-05 19:33:34
【问题描述】:

我已经设置了 Vuex 和 Vue Router。我想显示一个设置页面,以防用户帐户设置不正确。这是通过对后端进行 API 调用来实现的。结果存储在 Vuex 中并使用 getter 访问。该操作在根 Vuex 实例中的 beforeCreate 中调度:

new Vue({
  router,
  store,
  render: h => h(App),

  beforeCreate() {
    this.$store.dispatch("config/get");
  }
}).$mount("#app");

但是,我的路由器 beforeEach 从未收到 true,但根据 DevTools,getter 肯定会返回 true

router.beforeEach((to, next) => {
  if (!to.matched.some(record => record.meta.requiresSetup)) {
    next();
    return;
  }

  if (!store.getters["config/isConfigured"]) { // Executed every time.
    next("/setup");
    return;
  }

  next();
});

【问题讨论】:

    标签: vue.js vuex vue-router


    【解决方案1】:

    延迟应用加载

    即使钩子标记为async 并为某些异步操作执行await,也不能使用生命周期钩子来延迟加载。 Hooks 的目的不是允许操纵,只是为了提供对阶段的访问。

    不过,您可以延迟应用,只是在商店操作完成之前不加载它,但要意识到这对用户来说意味着一个空白页面,这是一种糟糕的用户体验。但您可以这样做:

    ma​​in.js

    const preload = async () => {
      await store.dispatch('config/get');    // `await` store action which returns a promise
      
      new Vue({
        store,
        router,
        render: (h) => h(App)
      }).$mount("#app");
    }
    
    preload();
    console.log('LOADING...');
    

    更好的方法

    最好调度该动作并且不要等待它。让 App.vue 加载并使用 v-if 显示启动屏幕,直到某些商店状态 isLoadingfalse

    ma​​in.js

    store.dispatch('config/get');
    
    new Vue({
      store,
      router,
      render: (h) => h(App)
    }).$mount("#app");
    

    App.vue

    <template>
    <div>
      <div v-if="isLoading">
        LOADING...     <!-- Attractive splash screen here -->
      </div>
      <div v-else>
        <router-view></router-view>  <!-- Don't show the router view until ready -->
      </div>
    </div>
    </template>
    

    完全移除导航防护并在 App.vue 中关注isLoading。一旦不再加载,根据帐户 getter 的状态重定向:

    computed: {
      ...mapState(['isLoading'])
    },
    methods: {
      redirect() {
        const path = this.$route.path;
        if (!this.$store.getters["config/isConfigured"]) {
          path !== '/setup' && this.$router.push({ path: '/setup' });
        } else {
          path !== '/' && this.$router.push({ path: '/' });
        }
      }
    },
    watch: {
      isLoading(val) {
        if (val === false) {
          this.redirect();
        }
      }
    }
    

    【讨论】:

    • 有趣的解决方案。不幸的是,我无法让它工作。只要loading 变成false,我就会被重定向到/setup。观察者似乎是多余的。它会引发错误“重复导航”。
    • 您可以通过to.path (in guard) 或this.$route.path (in component) 查看当前路由,避免冗余路由。顺便说一句,您的beforeEach 参数也是错误的,它是(to, from, next)。这个答案有一些变化,对于你所追求的东西可能会更好。您可以卸下导航防护装置或卸下手表。您可以移除手表并仅检查防护中的isLoading——如果应用仍在加载,则重定向到/setup
    【解决方案2】:

    这些生命周期回调具有同步行为。 你可以做的是类似的事情

    store.dispatch("config/get").then(() => {
    
      router.beforeEach((to, from, next) => {...}
    
      new Vue({...})
    
    })
    

    或者您可以在路由器的 beforeEach 中调用它并存储一些状态,如 isLoaded 并在 firstCall 上调用 store.dispatch 一次,其余调用使用存储状态

    【讨论】:

      猜你喜欢
      • 2020-11-26
      • 2019-02-24
      • 2011-12-05
      • 1970-01-01
      • 2019-07-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多