Состояние
Единое дерево состояния
Vuex использует единое дерево состояния — когда один объект содержит всё глобальное состояние приложения и служит «единственным источником истины». Это также означает, что в приложении будет только одно такое хранилище. Единое дерево состояния позволяет легко найти нужную его часть или делать снимки текущего состояния приложения в целях отладки.
Единое дерево состояния не противоречит модульности — в следующих главах изучим, как можно разделить состояние и мутации на под-модули.
Данные, которые хранятся во Vuex должны следовать тем же правилам, что и data
в экземпляре Vue, т.е. объект состояния должен быть простым. См. также: Vue#data.
Использование состояния Vuex в компонентах Vue
Итак, как использовать состояние хранилища в компонентах Vue? Поскольку хранилище Vuex реактивно, самый простой способ «получения» — просто вернуть часть состояния хранилища в вычисляемом свойстве:
// создадим компонент-счётчик:
const Counter = {
template: `<div>{{ count }}</div>`,
computed: {
count() {
return store.state.count
}
}
}
Любые изменения store.state.count
вызовут перерасчёт вычисляемого свойства и запуск связанных с ним обновлений DOM.
Однако этот подход заставляет компонент полагаться на синглтон глобального хранилища. При использовании модульной системы, это потребует импортировать хранилище в каждом компоненте, который использует его состояние, а также усложнит тестирование компонента.
Vuex «внедряет» хранилище во все дочерние компоненты из корневого компонента через систему плагинов Vue и будет доступно для них как this.$store
. Давайте обновим реализацию Counter
:
const Counter = {
template: `<div>{{ count }}</div>`,
computed: {
count() {
return this.$store.state.count
}
}
}
Вспомогательная функция mapState
Когда компонент должен использовать множество свойств или геттеров хранилища, объявлять все эти вычисляемые свойства может быть утомительно. В таких случаях можно использовать функцию mapState
, которая автоматически генерирует вычисляемые свойства:
// В полной сборке функция доступна через Vuex.mapState
import { mapState } from 'vuex'
export default {
// ...
computed: mapState({
// стрелочные функции могут сделать код очень кратким
count: state => state.count,
// передача строки 'count' аналогична записи `state => state.count`
countAlias: 'count',
// для доступа к локальному состоянию через `this`,
// необходимо использовать обычную функцию
countPlusLocalState(state) {
return state.count + this.localCount
}
})
}
Можно передавать массив строк в mapState
, когда имя сопоставляемого вычисляемого свойства совпадает с именем поддерева состояния:
computed: mapState([
// проксирует в this.count доступ к store.state.count
'count'
])
Оператор распространения объектов
Обратите внимание, mapState
возвращает объект. Как же его использовать в сочетании с другими локальными вычисляемыми свойствами? Для этого обычно приходилось использовать вспомогательные утилиты для объединения нескольких объектов в один, который передавать в computed
. Однако, с помощью оператора распространения объектов можно значительно упростить синтаксис:
computed: {
localComputed () { /* ... */ },
// смешиваем результат mapState с внешним объектом
...mapState({
// ...
})
}
Компоненты всё ещё могут иметь локальное состояние
Использование Vuex не означает, что нужно выносить всё состояние в хранилище. Хотя перемещение большей части состояния во Vuex, сделает мутации более явными и удобными для отладки, это также может привести к многословности и ненужному усложнению логики. Если часть состояния относится только к одному компоненту, лучше оставить его в качестве локального состояния. Необходимо взвесить все компромиссы и принять решение, соответствующее потребностям приложения и вектора его развития.