# Управление состоянием приложения
# Официальная Flux-подобная библиотека
Большие приложения часто могут усложняться из-за множества фрагментов состояния, разбросанных по многим компонентам, и взаимодействий между ними. Для решения этой проблемы Vue предлагает Vuex (opens new window) — собственную библиотеку для управления состоянием, вдохновлённую языком Elm. Она интегрируется с vue-devtools (opens new window) и позволяет заниматься отладкой с функцией «машиной времени» (opens new window).
# Информация для React-разработчиков
При переходе на Vue с React, может быть интересно как Vuex сравнивается с Redux (opens new window), самой популярной реализацией Flux в этой экосистеме. Redux не зависит от слоя представления, поэтому его можно легко использовать и с Vue с помощью простых привязок (opens new window). Vuex отличается тем, что он знает, что находится в приложении Vue. Это позволяет ему лучше интегрироваться и предлагать более интуитивно понятный API, улучшая процесс разработки.
# Создание простого контейнера состояния с нуля
Часто упускается из виду, что «источником истины» в приложениях Vue будет реактивный объект data
— экземпляр компонента лишь проксируют доступ к нему. Поэтому, если есть часть состояния, которая должна быть общей для нескольких экземпляров, то можно воспользоваться методом reactive, чтобы сделать объект реактивным:
const { createApp, reactive } = Vue
const sourceOfTruth = reactive({
message: 'Привет'
})
const appA = createApp({
data() {
return sourceOfTruth
}
}).mount('#app-a')
const appB = createApp({
data() {
return sourceOfTruth
}
}).mount('#app-b')
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<div id="app-a">Приложение A: {{ message }}</div>
<div id="app-b">Приложение B: {{ message }}</div>
2
3
Сейчас при изменении sourceOfTruth
оба приложения appA
и appВ
будут автоматически обновлять свои представления. Теперь есть единый источник истины, но отладка станет кошмаром. Любая часть данных может быть изменена в любой части приложения в любое время, не оставляя никаких следов.
const appB = createApp({
data() {
return sourceOfTruth
},
mounted() {
sourceOfTruth.message = 'Пока' // оба приложения теперь показывают 'Пока'
}
}).mount('#app-b')
2
3
4
5
6
7
8
Для решения этой проблемы можно адаптировать шаблон проектирования «состояние»:
const store = {
debug: true,
state: reactive({
message: 'Привет!'
}),
setMessageAction(newValue) {
if (this.debug) {
console.log('setMessageAction вызван с', newValue)
}
this.state.message = newValue
},
clearMessageAction() {
if (this.debug) {
console.log('clearMessageAction вызван')
}
this.state.message = ''
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Обратите внимание, что все действия, которые изменяют состояние хранилища, помещены в него. Такой подход к централизованному управлению состоянием позволяет легче понять, какие типы мутаций могут произойти и как они вызываются. Теперь, когда что-то пойдёт не так — у нас будет журнал событий с последовательностью действий, приведших к ошибке.
При этом в каждом экземпляре/компоненте может быть и своё собственное состояние, которым он управляет:
<div id="app-a">{{ sharedState.message }}</div>
<div id="app-b">{{ sharedState.message }}</div>
2
3
const appA = createApp({
data() {
return {
privateState: {},
sharedState: store.state
}
},
mounted() {
store.setMessageAction('Пока!')
}
}).mount('#app-a')
const appB = createApp({
data() {
return {
privateState: {},
sharedState: store.state
}
}
}).mount('#app-b')
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Совет
Не стоит заменять исходный объект состояния в своих действиях — компоненты и хранилище должны ссылаться на один и тот же объект для отслеживания мутаций.
Если продолжить развивать концепцию, в которой компонентам не разрешается напрямую изменять состояние хранилища, а вместо этого они должны отправлять события, которые уведомляют хранилище о необходимости выполнения каких-то действий, то в конечном итоге приходим к архитектуре Flux (opens new window). Преимущество этой архитектуры заключается в том, что можно записывать все мутации состояния, происходящие с хранилищем, и создавать продвинутые средства для отладки, такие как журналы мутаций, моментальные снимки и путешествие по истории изменений / «машину времени».
Это вновь возвращает к Vuex (opens new window), поэтому если дочитали до этого момента — пожалуй, пришло время попробовать!