如何在 Vuex 操作完成之前阻止 Vue 生命周期继续进行?

Posted

技术标签:

【中文标题】如何在 Vuex 操作完成之前阻止 Vue 生命周期继续进行?【英文标题】:How to stop Vue life cycle from moving on before Vuex actions have completed? 【发布时间】:2019-11-16 22:13:03 【问题描述】:

在我的应用程序中,我想在应用程序的其余部分启动之前初始化 3 个 Vuex 模块。但是,无论我尝试什么,我执行初始化的 Vue 实例生命周期钩子中的代码都会在 3 个模块完成初始化之前继续运行。

我在执行初始化的 Vuex 操作中的代码周围添加了一个承诺,以便我可以(a)等待调用生命周期钩子中的那些,但它不起作用。

我查看了使用 Axios 的示例 Vuex 代码,我必须使我的代码与此类似,但没有成功。

我尝试使用“Promise.all(...)”在“beforeCreate”生命周期挂钩中调用 init,但这仍然没有解决问题。

我的主 Vue 实例的代码如下所示:

new Vue(
  router,
  store,
  async beforeCreate() 
    await this.$store.dispatch('init')
  ,
  render: h => h(App)
).$mount('#app')

Vuex store 由 3 个模块组成,所有模块都有一个“init”动作。所有 3 个模块中的操作代码都是相同的。在下面的代码中有“XXX”的地方,每个模块的调用都会略有不同;

  init: (commit, dispatch) => 
    return new Promise((resolve, reject) => 
      console.log('Start of init of XXX');
      Axios.get(`api/xxx`).then(response => 
        return response.data;
      , error => 
        console.log('An error occured: ', error);
        reject(error);
      ).then(data => 
        const result = [];
        for (let key in data) 
          result.push(data[key]);
        

        console.log('The API call resulted in ' + result.length + ' lines of code');

        resolve(result);
        commit('ADD_XXX', result);
      )
    )
  

我期望的是“beforeCreate”代码会一直等待,直到 3 个 init 操作调用完全完成(即,直到所有承诺都已实现)。

我看到的是操作已启动(我在控制台中看到“Start of init...”日志)。但随后我看到其中一个应用程序组件的mounted() 函数中的代码开始执行,它不应该执行,因为如果存储尚未完全初始化,它将无法正常工作。

【问题讨论】:

我认为您不应该在应用程序的引导部分执行此操作。只需在您的 api 调用待处理时显示“正在初始化...”页面或其他内容。顺便说一句,您的商店已初始化,您的 init api 调用正在等待中。 【参考方案1】:

您不能暂停beforeCreate,将其设为async。当您点击await 时,它可能会在内部“暂停”,但从外部角度来看,它只是返回一个承诺。 Vue 不会注意到返回值,因此 Promise 将被忽略,并且生命周期将继续不间断。您可以做的是在您的 data 中添加一些状态并对其进行操作以达到所需的效果:

new Vue(
  router,
  store,
  data () 
    return 
      ready: false
    
  ,
  async beforeCreate() 
    await this.$store.dispatch('init')
    this.ready = true
  ,
  render (h) 
     if (this.ready) 
       return h(App)
     
  
).$mount('#app')

顺便说一句,您不需要在 init 中创建新的 Promise,您只需返回由 axios 创建的链式 Promise。

更新:

这是另一种方式,只是不要打电话给mount

new Vue(
  router,
  store,
  async beforeCreate() 
    await this.$store.dispatch('init')
    this.$mount('#app')
  ,
  render: h => h(App)
)

【讨论】:

并且 Vue 实例是否“知道”它必须一直等待直到“this.ready”(在渲染中)变为真,或者如果不是,则渲染会结束,而不是渲染有什么? 我的示例中的 render 函数最初不会渲染任何内容,但当 ready 更改时它将再次运行。 render 函数的行为很像计算属性,当反应依赖发生变化时会重新运行。所有组件模板都编译为 render 函数,根 Vue 实例通常不使用模板的唯一原因是避免需要完整的 Vue 构建。您习惯的所有自动重新渲染反应性功能只是 render 幕后功能。

以上是关于如何在 Vuex 操作完成之前阻止 Vue 生命周期继续进行?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Vue 的生命周期中显示来自 Vuex 存储的数据

vue-test-utils:如何在 mount() 生命周期钩子(使用 vuex)中测试逻辑?

路由vue-router仓库vuex前后台交互axiosdjango解决跨域问题前后台操作cookie

vue如何管理下载状态

vue生命周期-mounted和created的区别

如何在 Vuex 2 中设置初始状态?