Что такое Vuex и как он устроен?

Vuex — это официальная библиотека управления состоянием для Vue.js (в первую очередь для Vue 2, но совместима и с Vue 3). Она предоставляет централизованное хранилище (store) для всех компонентов приложения, позволяя предсказуемо управлять состоянием, организовывать бизнес-логику и обмен данными между компонентами. Vuex реализует концепции Flux/Redux, адаптированные под реактивность Vue.

Зачем нужен Vuex

Vuex решает проблему передачи данных между компонентами в сложных приложениях. Когда дерево компонентов становится глубоким, передача данных через props и события становится сложной и запутанной. Vuex предоставляет единый источник истины, позволяя любому компоненту получать или обновлять общее состояние, не нарушая реактивности.

Структура Vuex

Vuex основан на четкой архитектуре с четырьмя основными элементами:

  1. State — централизованное хранилище данных.

  2. Getters — вычисляемые свойства на основе state.

  3. Mutations — синхронные функции, изменяющие состояние.

  4. Actions — асинхронная логика, которая вызывает mutations.

  5. Modules — разбиение store на части (при большом приложении).

Пример базового Vuex store

import { createStore } from 'vuex';
const store = createStore({
state() {
return {
count: 0
};
},
getters: {
doubleCount(state) {
return state.count \* 2;
}
},
mutations: {
increment(state) {
state.count++;
},
setCount(state, payload) {
state.count = payload;
}
},
actions: {
asyncIncrement({ commit }) {
setTimeout(() => {
commit('increment');
}, 1000);
}
}
});

В Vue 2 store создавался через new Vuex.Store({ ... }), в Vue 3 — через createStore.

Использование store в компонентах

Чтение из state:

import { useStore } from 'vuex';
import { computed } from 'vue';
setup() {
const store = useStore();
const count = computed(() => store.state.count);
return { count };
}

Использование геттеров:

const double = computed(() => store.getters.doubleCount);

Вызов мутаций:

const increment = () => store.commit('increment');

Вызов экшенов:

const asyncIncrement = () => store.dispatch('asyncIncrement');

Отличия между actions и mutations

Характеристика Mutations Actions
Тип Синхронные Асинхронные возможны
--- --- ---
Изменяют state Да Нет (но вызывают mutations)
--- --- ---
Где используются Прямо в компонентах Для сетевых запросов, таймеров
--- --- ---
Пример вызова commit('increment') dispatch('asyncIncrement')
--- --- ---

Модули (modules)

Vuex позволяет разбивать store на модули, каждый из которых содержит собственные state, getters, mutations, actions.

const moduleA = {
namespaced: true,
state() {
return { count: 0 };
},
mutations: {
increment(state) {
state.count++;
}
}
};
const store = createStore({
modules: {
a: moduleA
}
});

Вызов:

store.commit('a/increment');

Модули могут быть вложенными и динамически регистрируемыми (например, при загрузке страницы).

namespaced: true

По умолчанию все модули используют глобальные имена мутаций и геттеров. При namespaced: true все обращения происходят с префиксом:

store.dispatch('a/asyncIncrement');
store.getters\['a/doubleCount'\];

Реактивность и ограничения

Vuex использует реактивность Vue под капотом. Поэтому при обновлении state, все компоненты, подписанные на это состояние (через computed()), автоматически перерисуются.

Ограничения:

  • нельзя напрямую менять state (например: store.state.count++ вне мутаций);

  • мутации должны быть синхронными — иначе состояние теряет предсказуемость;

  • экшены не могут напрямую менять state, только через мутации.

Интеграция с devtools

Vuex хорошо интегрируется с Vue Devtools:

  • можно отслеживать каждый commit, dispatch, payload, старое и новое состояние;

  • поддерживает time-travel debugging (перемотка состояний);

  • можно экспортировать и импортировать состояния.

Динамическая регистрация модулей

Vuex позволяет добавлять модули во время выполнения, например:

store.registerModule('user', {
state: { name: 'admin' }
});

Удаление:

store.unregisterModule('user');

Это удобно при ленивой загрузке маршрутов или функциональности.

Ограничения и замены Vuex

Vuex был популярен в эпоху Vue 2, но с появлением Composition API многие приложения переходят на Pinia — более лёгкую и современную альтернативу, также официально поддерживаемую Vue-командой. Pinia предоставляет тот же функционал, но с более простой архитектурой, типизацией и лучшей интеграцией с Vue 3.