Действия
Действия похожи на мутации, но с отличиями:
- Вместо изменения состояния, действия вызывают мутации.
- Действия могут содержать произвольные асинхронные операции.
Зарегистрируем простое действие:
const store = createStore({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
},
actions: {
increment (context) {
context.commit('increment')
}
}
})
Обработчики действий получают объект контекста, который предоставляет тот же набор методов/свойств экземпляра хранилища, поэтому вы можете вызвать context.commit для выполнения мутации или получить доступ к состоянию и геттерам через context.state и context.getters. Мы даже можем вызвать другие действия с помощью context.dispatch. Мы увидим, почему этот объект контекста не является самим экземпляром хранилища, когда мы рассмотрим модули позже.
На практике мы часто используем деструктуризацию ES2015 аргументов, чтобы немного упростить код (особенно когда нам нужно вызвать commit несколько раз):
actions: {
increment ({ commit }) {
commit('increment')
}
}
Отправка действий
Действия вызываются с помощью метода store.dispatch:
store.dispatch('increment')
Это может показаться странным на первый взгляд: если мы хотим увеличить счётчик, почему бы нам не вызвать store.commit('increment') напрямую? Помните, что мутации должны быть синхронными. Действия — нет. Мы можем выполнить асинхронные операции внутри действия:
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 и выполнение нескольких мутаций:
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)
)
}
}
Обратите внимание, что мы выполняем поток асинхронных операций и записываем побочные эффекты (изменения состояния) действия, выполняя их.
Отправка действий в компонентах
Вы можете отправить действия в компонентах с помощью 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, который выполняется, когда все вызываемые обработчики были выполнены.
© 2015–present Evan You
Licensed under the MIT License.
https://next.vuex.vuejs.org/guide/actions.html