操作

操作类似于 Mutation,区别在于

  • 操作不会直接修改状态,而是提交 Mutation。
  • 操作可以包含任意异步操作。

让我们注册一个简单的操作

const store = createStore({
  state: {
    count: 0
  },
  mutations: {
    increment (state) {
      state.count++
    }
  },
  actions: {
    increment (context) {
      context.commit('increment')
    }
  }
})

操作处理程序接收一个上下文对象,该对象公开 store 实例上的相同方法/属性集,因此您可以调用 context.commit 提交 Mutation,或通过 context.statecontext.getters 访问状态和 Getter。我们甚至可以使用 context.dispatch 调用其他操作。当我们稍后介绍 模块 时,我们将看到为什么此上下文对象本身不是 store 实例。

在实践中,我们经常使用 ES2015 参数解构 来简化代码(尤其是在我们需要多次调用 commit 时)

actions: {
  increment ({ commit }) {
    commit('increment')
  }
}

分发操作

操作使用 store.dispatch 方法触发

store.dispatch('increment')

乍一看这可能很奇怪:如果我们想增加计数,为什么不直接调用 store.commit('increment')?请记住,**Mutation 必须是同步的**。操作则不是。我们可以在操作中执行**异步**操作

actions: {
  incrementAsync ({ commit }) {
    setTimeout(() => {
      commit('increment')
    }, 1000)
  }
}

操作支持相同的有效负载格式和对象样式分发

// dispatch with a payload
store.dispatch('incrementAsync', {
  amount: 10
})

// dispatch with an object
store.dispatch({
  type: 'incrementAsync',
  amount: 10
})

一个更实用的真实世界操作示例将是结账购物车的操作,这涉及**调用异步 API** 和**提交多个 Mutation**

actions: {
  checkout ({ commit, state }, products) {
    // save the items currently in the cart
    const savedCartItems = [...state.cart.added]
    // send out checkout request, and optimistically
    // clear the cart
    commit(types.CHECKOUT_REQUEST)
    // the shop API accepts a success callback and a failure callback
    shop.buyProducts(
      products,
      // handle success
      () => commit(types.CHECKOUT_SUCCESS),
      // handle failure
      () => commit(types.CHECKOUT_FAILURE, savedCartItems)
    )
  }
}

请注意,我们正在执行异步操作流,并通过提交它们来记录操作的副作用(状态 Mutation)。

在组件中分发操作

您可以在组件中使用 this.$store.dispatch('xxx') 分发操作,或者使用 mapActions 辅助函数,该函数将组件方法映射到 store.dispatch 调用(需要根 store 注入)

import { mapActions } from 'vuex'

export default {
  // ...
  methods: {
    ...mapActions([
      'increment', // map `this.increment()` to `this.$store.dispatch('increment')`

      // `mapActions` also supports payloads:
      'incrementBy' // map `this.incrementBy(amount)` to `this.$store.dispatch('incrementBy', amount)`
    ]),
    ...mapActions({
      add: 'increment' // map `this.add()` to `this.$store.dispatch('increment')`
    })
  }
}

组合操作

操作通常是异步的,那么我们如何知道操作何时完成?更重要的是,我们如何将多个操作组合在一起以处理更复杂的异步流?

首先要知道的是,store.dispatch 可以处理由触发的操作处理程序返回的 Promise,它也返回 Promise

actions: {
  actionA ({ commit }) {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        commit('someMutation')
        resolve()
      }, 1000)
    })
  }
}

现在您可以这样做

store.dispatch('actionA').then(() => {
  // ...
})

以及在另一个操作中

actions: {
  // ...
  actionB ({ dispatch, commit }) {
    return dispatch('actionA').then(() => {
      commit('someOtherMutation')
    })
  }
}

最后,如果我们使用 async / await,我们可以像这样组合我们的操作

// assuming `getData()` and `getOtherData()` return Promises

actions: {
  async actionA ({ commit }) {
    commit('gotData', await getData())
  },
  async actionB ({ dispatch, commit }) {
    await dispatch('actionA') // wait for `actionA` to finish
    commit('gotOtherData', await getOtherData())
  }
}

store.dispatch 可以触发不同模块中的多个操作处理程序。在这种情况下,返回值将是一个 Promise,当所有触发的处理程序都已解析时,它将解析。