首页 > 解决方案 > 如何正确链接 Vuex 操作,并在调用之间正确改变状态?

问题描述

我的应用程序中有一个Vuex商店,它定义gettersactionsmutations。现在,一个操作从 API 请求数据,并将接收到的数据提交给操纵状态的突变。此特定操作(名为initConfiguration)会加载一些元数据和配置,这些元数据和配置必须先应用于存储,然后才能执行后续操作。在我的根组件中,我在mounted生命周期挂钩函数中有一些初始化代码,如下所示:

new Vue({
  el: '#app',
  store,
  render: h => h(App),
  mounted() {
    store.dispatch('initConfiguration').then(() => {
      store.dispatch('loadData')
    })
  }
})

我面临的问题是在调用下一个操作之前状态尚未更改loadData,因此由于缺少/未初始化的数据,此操作严重失败。由于最终可能会调用多个动作,因此我想避免loadData直接从动作中分派initConfiguration动作(据我所知,必须避免通过突变调用动作)。

这是我的商店实现...

export default Vuex.Store({
  state: {
    metadata: {
      initialized: false,
      config: { }
    }
  },
  mutations: { 
    setConfiguration(state, config) {
      state.metadata.config = config
      state.metadata.initialized = true
    }
  },
  actions: {
    initConfiguration({commit}) {
      axios.get('configuration').then((response) => {
        commit('setConfiguration', response.data)
      })
    },
    loadData({commit, state}) {
      axios.get(state.metadata.config.tenantDataUrl) // crashes here due to undefined data
        .then((response) => { ... });
    }
  }
})

如何正确链接操作,并确保状态在两者之间得到更新?

标签: javascriptvue.jsvuejs2vuex

解决方案


您需要返回您的 axios 承诺。为每个 axios 调用添加一个返回值,您现有的代码就可以工作了。

你也可以这样重写

new Vue({
  el: '#app',
  store,
  render: h => h(App),
  async mounted() {
    await store.dispatch('initConfiguration')
    await store.dispatch('loadData')    
  }
})

.

export default Vuex.Store({
  state: {
    metadata: {
      initialized: false,
      config: { }
    }
  },
  mutations: { 
    setConfiguration(state, config) {
      state.metadata.config = config
      state.metadata.initialized = true
    }
  },
  actions: {
    async initConfiguration({commit}) {
      const response = await axios.get('configuration')
      commit('setConfiguration', response.data)
    },
    async loadData({commit, state}) {
      const response = await axios.get(state.metadata.config.tenantDataUrl) // crashes here due to undefined data
     // do whatever with response, or try/catch
    }
  }
})

如果您需要在每一步更新 vue 模板,请添加此

new Vue({
  el: '#app',
  store,
  render: h => h(App),
  async mounted() {
    await store.dispatch('initConfiguration')
    await this.$nextTick() // cause vue to run getters and update computeds
    await store.dispatch('loadData')    
  }
})

推荐阅读