Мутации
Единственный способ фактически изменить состояние в хранилище Vuex — это выполнить мутацию. Мутации Vuex очень похожи на события: каждая мутация имеет строковый **тип** и **обработчик**. Функция обработчика — это место, где мы выполняем фактические изменения состояния, и она будет получать состояние в качестве первого аргумента:
const store = new Vuex.Store({
state: {
count: 1
},
mutations: {
increment (state) {
// mutate state
state.count++
}
}
})
Вы не можете напрямую вызвать обработчик мутации. Представьте себе это как регистрацию события: «Когда срабатывает мутация с типом increment, вызовите этот обработчик». Чтобы вызвать обработчик мутации, необходимо вызвать store.commit с его типом:
store.commit('increment')
Выполнение мутации с данными
Вы можете передать дополнительный аргумент в store.commit, который называется **данными** мутации:
// ...
mutations: {
increment (state, n) {
state.count += n
}
}
store.commit('increment', 10)
В большинстве случаев данные должны быть объектом, чтобы они могли содержать несколько полей, и записанная мутация также будет более описательной:
// ...
mutations: {
increment (state, payload) {
state.count += payload.amount
}
}
store.commit('increment', {
amount: 10
})
Мутация в стиле объекта
Альтернативный способ выполнения мутации — использование объекта, имеющего свойство type:
store.commit({
type: 'increment',
amount: 10
})
При использовании мутации в стиле объекта весь объект будет передан в качестве данных обработчикам мутаций, поэтому обработчик остаётся тем же:
mutations: {
increment (state, payload) {
state.count += payload.amount
}
}
Мутации следуют правилам реактивности Vue
Поскольку состояние хранилища Vuex делается реактивным с помощью Vue, при мутации состояния компоненты Vue, наблюдающие за состоянием, будут автоматически обновляться. Это также означает, что мутации Vuex подчиняются тем же ограничениям реактивности, что и обычные Vue:
Предпочтительно инициализировать начальное состояние вашего хранилища со всеми желаемыми полями с самого начала.
При добавлении новых свойств к объекту вы должны либо:
Использовать
Vue.set(obj, 'newProp', 123), или-
Заменить этот объект новым. Например, используя синтаксис разброса объектов, мы можем написать его так:
state.obj = { ...state.obj, newProp: 123 }
Использование констант для типов мутаций
В различных реализациях Flux часто встречается практика использования констант для типов мутаций. Это позволяет коду использовать такие инструменты, как анализаторы кода, а размещение всех констант в одном файле позволяет вашим коллегам быстро ознакомиться с возможными мутациями во всём приложении:
// mutation-types.js
export const SOME_MUTATION = 'SOME_MUTATION'
// store.js
import Vuex from 'vuex'
import { SOME_MUTATION } from './mutation-types'
const store = new Vuex.Store({
state: { ... },
mutations: {
// we can use the ES2015 computed property name feature
// to use a constant as the function name
[SOME_MUTATION] (state) {
// mutate state
}
}
})
Использование констант в значительной степени зависит от предпочтений — это может быть полезно в больших проектах с множеством разработчиков, но это совершенно необязательно, если вы их не используете.
Мутации должны быть синхронными
Важно помнить, что **функции обработчика мутаций должны быть синхронными**. Почему? Рассмотрим следующий пример:
mutations: {
someMutation (state) {
api.callAsyncMethod(() => {
state.count++
})
}
}
Теперь представьте, что мы отлаживаем приложение и смотрим на журналы мутаций devtools. Для каждой зарегистрированной мутации devtools должен захватить «до» и «после» состояния. Однако асинхронный обратный вызов внутри примера мутации выше делает это невозможным: обратный вызов ещё не вызван при выполнении мутации, и нет способа для devtools узнать, когда обратный вызов будет фактически вызван — любые изменения состояния, выполненные в обратном вызове, фактически не отслеживаются!
Выполнение мутаций в компонентах
Вы можете выполнить мутации в компонентах с помощью this.$store.commit('xxx'), или используйте вспомогательную функцию mapMutations, которая сопоставляет методы компонента с вызовами store.commit (требуется инъекция корневого store):
import { mapMutations } from 'vuex'
export default {
// ...
methods: {
...mapMutations([
'increment', // map `this.increment()` to `this.$store.commit('increment')`
// `mapMutations` also supports payloads:
'incrementBy' // map `this.incrementBy(amount)` to `this.$store.commit('incrementBy', amount)`
]),
...mapMutations({
add: 'increment' // map `this.add()` to `this.$store.commit('increment')`
})
}
}
Дальше — Действия
Асинхронность в сочетании с мутациями состояния может сильно затруднить понимание вашего приложения. Например, когда вы вызываете два метода, оба с асинхронными обратными вызовами, которые изменяют состояние, как вы узнаете, когда они были вызваны и какой обратный вызов был вызван первым? Именно поэтому мы хотим разделить эти два понятия. В Vuex **мутации являются синхронными транзакциями**:
store.commit('increment')
// any state change that the "increment" mutation may cause
// should be done at this moment.
Для обработки асинхронных операций давайте рассмотрим Действия.
← Получатели Действия →
© 2015–present Evan You
Licensed under the MIT License.
https://vuex.vuejs.org/guide/mutations.html