Вам может не понадобиться Vuex с Vue 3
Vuex — отличная библиотека для управления состоянием. Это просто и хорошо интегрируется с Vue. Зачем кому-то покидать Vuex? Причина может заключаться в том, что предстоящий выпуск Vue 3 раскрывает базовую систему реактивности и вводит новые способы структурирования вашего приложения. Новая система реактивности настолько мощна, что ее можно использовать для централизованного управления состоянием.
Вам нужно общее состояние?
Бывают обстоятельства, когда поток данных между несколькими компонентами становится настолько сложным, что требуется централизованное управление состоянием. К таким обстоятельствам относятся:
- Несколько компонентов, использующих одни и те же данные
- Несколько корней с доступом к данным
- Глубокая вложенность компонентов
Если ни один из вышеперечисленных случаев не соответствует действительности, ответ прост, нужен он вам или нет. Вам это не нужно.
Но что делать, если у вас есть один из этих случаев? Прямой ответ — использовать Vuex. Это проверенное в бою решение, и оно достойно работает.
Но что, если вы не хотите добавлять еще одну зависимость или находите настройку слишком сложной? Новая версия Vue 3 вместе с Composition API может решить эти проблемы с помощью встроенных методов.
Новое решение
Общее состояние должно соответствовать двум критериям:
- реактивность: при изменении состояния компоненты, использующие их, также должны обновляться
- доступность: состояние доступно в любом из компонентов
Реактивность
Vue 3 раскрывает свою систему реактивности с помощью многочисленных функций. Вы можете создать реактивную переменную с помощью reactive
функция (альтернативой может быть ref
функция).
import { reactive } from 'vue';
export const state = reactive({ counter: 0 });
Объект вернулся из reactive
функция представляет собой Proxy
объект, который может отслеживать изменения своих свойств. При использовании в шаблоне компонента компонент перерисовывается всякий раз, когда изменяется реактивное значение.
<template>
<div>{{ state.counter }}</div>
<button type="button" @click="state.counter++">Increment</button>
</template>
<script>
import { reactive } from 'vue';
export default {
setup() {
const state = reactive({ counter: 0 });
return { state };
}
};
</script>
Доступность
Приведенный выше пример отлично подходит для одного компонента, но другие компоненты не могут получить доступ к состоянию. Чтобы преодолеть это, вы можете сделать любое значение доступным внутри приложения Vue 3 с помощью provide
а также inject
методы.
import { reactive, provide, inject } from 'vue';
export const stateSymbol = Symbol('state');
export const createState = () => reactive({ counter: 0 });
export const useState = () => inject(stateSymbol);
export const provideState = () => provide(
stateSymbol,
createState()
);
Когда вы проходите Symbol
как ключ и ценность для provide
метод, это значение будет доступно для любого дочернего компонента через inject
метод. Ключ использует тот же Symbol
имя при предоставлении и получении значения.
Таким образом, если вы укажете значение для самого верхнего компонента, оно будет доступно во всех компонентах. Кроме того, вы также можете позвонить provide
на основном экземпляре приложения.
import { createApp, reactive } from 'vue';
import App from './App.vue';
import { stateSymbol, createState } from './store';
const app = createApp(App);
app.provide(stateSymbol, createState());
app.mount('#app');
<script>
import { useState } from './state';
export default {
setup() {
return { state: useState() };
}
};
</script>
Делаем его надежным
Приведенное выше решение работает, но имеет недостаток: вы не знаете, кто что модифицирует. Состояние можно изменить напрямую, ограничений нет.
Вы можете сделать свое состояние защищенным, обернув его readonly
функция. Он покрывает переданную переменную в Proxy
объект, который предотвращает любую модификацию (выдает предупреждение, когда вы пытаетесь это сделать). Мутации могут обрабатываться отдельными функциями, имеющими доступ к доступному для записи хранилищу.
import { reactive, readonly } from 'vue';
export const createStore = () => {
const state = reactive({ counter: 0 });
const increment = () => state.counter++;
return { increment, state: readonly(state) };
}
Внешний мир будет иметь доступ только к состоянию только для чтения, и только экспортированные функции могут изменять состояние, доступное для записи.
Защищая состояние от нежелательных модификаций, новое решение относительно близко к Vuex.
Резюме
Используя систему реактивности и механизм внедрения зависимостей Vue 3, мы перешли от локального состояния к централизованному управлению состоянием, которое может заменить Vuex в небольших приложениях.
У нас есть объект состояния, который доступен только для чтения и реагирует на изменения в шаблонах. Состояние можно изменить только с помощью определенных методов, таких как действия/мутации в Vuex. Вы можете определить дополнительные геттеры с помощью computed
функция.
Vuex имеет больше функций, таких как обработка модулей, но иногда нам это не нужно.
Если вы хотите взглянуть на Vue 3 и попробовать этот подход к управлению состоянием, взгляните на моя игровая площадка Vue 3.