Какие альтернативы Vuex вы использовали и почему?
С момента выхода Vue 3 и появления Composition API, сообщество начало активно искать альтернативы Vuex, ориентированные на модульность, простоту и тесную интеграцию с реактивностью ref и reactive. Vuex, особенно в версиях 3 и 4, имел устаревший синтаксис с обязательными mutations, actions, громоздкой структурой и отсутствием type-safety по умолчанию. В больших и современных проектах начали использоваться более легковесные и декларативные подходы. Ниже представлены ключевые альтернативы Vuex, которые я использовал, с техническим обоснованием и реализационными примерами.
1. Pinia
Почему выбрана:
Pinia — официально рекомендуемая альтернатива Vuex от команды Vue. Полностью совместима с Vue 3, поддерживает Composition API, TypeScript из коробки, SSR и Devtools. Простая, модульная, без разделения на mutations, actions и getters.
Пример:
// stores/useUserStore.ts
import { defineStore } from 'pinia'
export const useUserStore = defineStore('user', {
state: () => ({
name: '',
isAdmin: false
}),
actions: {
login(name: string) {
this.name = name
}
},
getters: {
isLoggedIn: (state) => !!state.name
}
})
// в компоненте
const user = useUserStore()
user.login('admin')
Преимущества:
-
Простота (никаких mutations)
-
Поддержка devtools, SSR
-
storeToRefs() для реактивных ссылок
-
Расширения (pinia-plugin-persistedstate, pinia-orm)
2. Composition API + Composables (без Pinia)
Почему выбрана:
При простом или среднесложном состоянии можно обойтись без полноценного стор-решения. Используется подход composable-функций с использованием ref, reactive и обычных функций.
Пример:
// useCart.ts
import { ref } from 'vue'
const items = ref(\[\])
export function useCart() {
const addItem = (item) => items.value.push(item)
const totalItems = computed(() => items.value.length)
return { items, addItem, totalItems }
}
// в компоненте
const { items, addItem } = useCart()
Преимущества:
-
Не требует сторонних библиотек
-
Идеально для локального или модульного состояния
-
Отлично работает с TypeScript
Минусы:
-
Нет devtools
-
Сложно масштабировать глобальное состояние без соглашений
3. Vue Observable (Vue 2, до Composition API)
Почему использовалась:
До появления Composition API и до Vuex 4 некоторые проекты использовали Vue.observable() для создания реактивного состояния вручную.
// store.js
import Vue from 'vue'
export const store = Vue.observable({ count: 0 })
export const mutations = {
increment() {
store.count++
}
}
Минусы:
-
Нет модульности
-
Не поддерживается во Vue 3
4. Redux Toolkit (в гибридных проектах с Vue и React)
Почему использовалась:
В проекте с общей бизнес-логикой между React и Vue использовался Redux Toolkit с экспортируемыми стор-конфигурациями.
// slice.ts
const counterSlice = createSlice({
name: 'counter',
initialState: { value: 0 },
reducers: {
increment: (state) => {
state.value++
}
}
})
Интеграция с Vue:
Использование @reduxjs/toolkit через store.subscribe() + computed для реактивности. Такой подход оправдан при необходимости использования единого хранилища между фреймворками.
5. Zustand (в микрофронтах или Web Components)
Почему использовалась:
Zustand — минималистичный, эффективный store от авторов Jotai/React Spring. Использовался в микрофронтах, взаимодействующих с Vue и React.
const useStore = create((set) => ({
count: 0,
inc: () => set((state) => ({ count: state.count + 1 }))
}))
Для Vue применялся reactive(useStore.getState()) и store.subscribe().
6. RxJS (реактивная модель)
Почему использовалась:
Для сложных асинхронных сценариев (формы, валидация, данные из WebSocket) использовались BehaviorSubject, Observable, интеграция с Vue через ref() и подписки.
const subject = new BehaviorSubject(0)
export function useRxCount() {
const count = ref(subject.value)
subject.subscribe((val) => {
count.value = val
})
const increment = () => subject.next(subject.value + 1)
return { count, increment }
}
Преимущества:
-
Явное управление потоками
-
Обработка множественных событий и состояний
-
Отлично сочетается с Vue's watchEffect и ref
Минусы:
-
Высокий порог входа
-
Избыточен для большинства CRUD-приложений
7. VueUse и useStorage, useSessionStorage
Почему использовалась:
В проектах, где состояние нужно синхронизировать с localStorage/sessionStorage, использовались готовые решения из VueUse.
import { useStorage } from '@vueuse/core'
const token = useStorage('auth_token', '')
Преимущества:
-
Реактивность + персистентность
-
Нет необходимости создавать отдельный store
-
Отлично подходит для settings/preferences
8. Apollo Client Cache (в GraphQL-проектах)
Почему использовалась:
В GraphQL-приложениях (например, при использовании Hasura) данные кэшировались через Apollo Client, который автоматически управлял состоянием.
import { useQuery } from '@vue/apollo-composable'
const { result } = useQuery(GET_USER)
Также возможна запись кэша вручную:
apolloClient.writeQuery({
query: GET_USER,
data: { user: { id: 1, name: 'Alex' } }
})
Преимущества:
-
Нет необходимости дублировать состояние между API и store
-
Автоматическая нормализация, рефетчи, обновление кэша
9. Effector (в проекте с высокими требованиями к предсказуемости)
Effector — декларативный и функциональный state manager с чёткой моделью и масштабируемостью. В Vue используется с обёртками (effector-vue).
import { createStore, createEvent } from 'effector'
const increment = createEvent()
const $count = createStore(0).on(increment, (state) => state + 1)
Для Vue:
import { useStore } from 'effector-vue/composition'
const count = useStore($count)
Преимущества:
-
Поддержка event-driven архитектуры
-
Хорошая масштабируемость
-
Идеален для систем с высокой сложностью состояний
10. Сравнительная таблица
Инструмент | Vue 3 Support | Devtools | TypeScript | SSR | Подходит для |
---|---|---|---|---|---|
Pinia | ✅ | ✅ | ✅ | ✅ | Любые Vue 3 приложения |
--- | --- | --- | --- | --- | --- |
Composables (ref) | ✅ | ❌ | ✅ | ✅ | Простые, модульные задачи |
--- | --- | --- | --- | --- | --- |
Vue.observable | ❌ (только Vue 2) | ❌ | ❌ | ❌ | Легаси-проекты |
--- | --- | --- | --- | --- | --- |
Redux Toolkit | ✅ (опционально) | ✅ | ✅ | ✅ | Кросс-фреймворк проекты |
--- | --- | --- | --- | --- | --- |
Zustand | ⚠️ через обёртку | ❌ | ✅ | ❌ | Микрофронты, shared stores |
--- | --- | --- | --- | --- | --- |
RxJS | ✅ | ❌ | ✅ | ✅ | Сложные async-сценарии |
--- | --- | --- | --- | --- | --- |
VueUse | ✅ | ❌ | ✅ | ✅ | Персистентные состояния |
--- | --- | --- | --- | --- | --- |
Apollo Client | ✅ | ✅ | ✅ | ✅ | GraphQL-клиенты |
--- | --- | --- | --- | --- | --- |
Effector | ✅ | ✅ | ✅ | ✅ | Высоконагруженные SPA |
--- | --- | --- | --- | --- | --- |