Vuex долгое время был стандартным решением для централизованного управления состоянием во Vue-приложениях. Он обеспечивал строгую архитектуру, предсказуемость и удобство отладки. Однако с выходом Vue 3 и обновлением экосистемы выявились ограничения Vuex: избыточная шаблонность, слабая типизация, сложность масштабирования и неестественная интеграция с Composition API. В результате основным направлением развития стал переход на Pinia — более лёгкое, гибкое и современное хранилище состояния.
Vuex основан на едином глобальном хранилище, разбитом на модули. Каждый модуль включает:
stategettersmutationsactionsЖёсткое разделение между мутациями и действиями увеличивает объём кода и усложняет поддержку.
Pinia использует концепцию независимых хранилищ (stores), где:
Такой подход ближе к нативной модели JavaScript и Composition API.
Перед началом миграции требуется:
Миграция возможна поэтапно, без полного отказа от Vuex на старте.
Pinia подключается как плагин Vue-приложения и не требует сложной конфигурации:
import { createPinia } from 'pinia'
const pinia = createPinia()
app.use(pinia)
Pinia поддерживает devtools, SSR и динамическое создание хранилищ.
Vuex:
state: () => ({
count: 0
})
Pinia:
state: () => ({
count: 0
})
Синтаксис практически идентичен, но состояние в Pinia становится реактивным без дополнительных обёрток.
Vuex:
getters: {
doubleCount: state => state.count * 2
}
Pinia:
getters: {
doubleCount: state => state.count * 2
}
В Pinia getters могут использовать this, что упрощает
композицию логики:
doubleCount() {
return this.count * 2
}
Vuex требует строгого разделения:
mutations: {
increment(state) {
state.count++
}
},
actions: {
incrementAsync({ commit }) {
setTimeout(() => commit('increment'), 1000)
}
}
Pinia объединяет изменения состояния и асинхронную логику:
actions: {
increment() {
this.count++
},
async incrementAsync() {
await delay(1000)
this.increment()
}
}
Отсутствие мутаций снижает шаблонность и делает код компактнее.
Pinia изначально проектировалась с учётом TypeScript. Типы состояния,
getters и actions выводятся автоматически. В отличие от Vuex, не
требуется ручное описание типов для commit и
dispatch.
const useCounterStore = defineStore('counter', {
state: () => ({
count: 0
})
})
TypeScript корректно определяет count и методы хранилища
без дополнительной конфигурации.
Vuex (Options API):
computed: {
count() {
return this.$store.state.count
}
}
Pinia (Composition API):
const counter = useCounterStore()
counter.count
Pinia поддерживает деструктуризацию с сохранением реактивности через
storeToRefs.
Vuex-модули преобразуются в отдельные stores Pinia. Пространства имён больше не требуются, так как каждый store изолирован.
Vuex:
modules: {
user,
cart
}
Pinia:
useUserStore()
useCartStore()
Такой подход улучшает читаемость и повторное использование логики.
Pinia может быть внедрена параллельно с Vuex. Это позволяет:
Компоненты могут одновременно использовать оба хранилища без конфликтов.
Pinia официально поддерживается в Nuxt 3 и полностью интегрирована в SSR. Состояние корректно сериализуется и гидратируется без дополнительной логики, в отличие от Vuex, где часто требовалась ручная настройка.
Pinia использует Vue Devtools и предоставляет:
История действий отображается как обычные вызовы функций, что упрощает анализ.
Миграция с Vuex на Pinia приводит к:
Pinia не является прямой копией Vuex, а представляет собой эволюцию подхода к управлению состоянием во Vue-приложениях.