Вам возможно не нужен Vuex с Vue 3
Оригинальная статья: Gábor Soós — You Might Not Need Vuex with Vue 3
Vuex — это потрясающая библиотека управления централизованным состоянием. Она проста и хорошо интегрируется с Vue. Зачем кому то отказываться от использования Vuex? Причина может заключаться в том, что в следующем выпуске Vue 3 будет представлена базовая система реактивности и представлены новые способы структурирования приложения. Новая система реактивности настолько мощна, что ее можно использовать и для централизованным управлением состоянием.
Вам нужно общее состояние?
Существуют обстоятельства, когда поток данных между несколькими компонентами становится настолько сложным, что вам требуется централизованное управление состоянием. Эти обстоятельства включают в себя:
- Несколько компонентов одного уровня, которые используют одни и те же данные
- Иерархия компонентов с доступом к данным верхнего уровня
- Глубокое вложение компонентов
Обычно в таких случаях будет разумным использование Vuex. Это проверенное в бою решение, которое хорошо делает свою работу.
Но что, если вы не хотите добавлять другие зависимости или находите такую компоновку слишком сложной? Новая версия Vue 3 вместе с API Composition может решить эти проблемы с помощью встроенных методов.
Новое решение
Общее состояние должно соответствовать двум критериям:
- реактивность: при изменении состояния компоненты, использующие их, также должны обновляться
- доступность: состояние может быть доступно в любом из компонентов
Реактивность
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 при предоставлении (providing) и получении (retrieving) значения.
Таким образом, если вы предоставите (provide) значение для самого верхнего компонента, оно будет доступно во всех компонентах. Кроме того, вы также можете вызвать 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) }; }
Внешний мир будет иметь доступ к state только для чтения, и только экспортированные внутренние функции могут изменять состояние записи.
Защищая состояние от нежелательных модификаций, новое решение становиться таким как Vuex.
Заключение
Используя систему реактивности и механизм внедрения зависимостей Vue 3, мы перешли от локального состояния к централизованному управлению состояниями, которое может заменить Vuex в небольших приложениях.
У нас есть объект состояния, который доступен только для чтения и реагирует на изменения в шаблонах. Состояние может быть изменено только с помощью специальных методов, точно таких же как actions/mutations в Vuex. Вы можете определить дополнительные геттеры с помощью вычисляемой (computed) функции.
Vuex имеет больше функционала, для обработки модулей, но чаще всего нам это не нужно.
Если вы хотите взглянуть на Vue 3 и попробовать этот подход к управлению состоянием, взгляните на мою песочницу Vue 3.
> взгляните на мою площадку Vue 3.
Всё же — песочницу.
Нам нужен. Особенно в средних и крупных приложениях.
Кстати, в третей версии, как в Nuxt.js, могли-бы включить Vuex по-умолчанию. Или, хотя-бы, при инициализации спросить, предустанавливать или нет..