Миграция с Vuex

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

Архитектурные различия Vuex и Pinia

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

  • state
  • getters
  • mutations
  • actions

Жёсткое разделение между мутациями и действиями увеличивает объём кода и усложняет поддержку.

Pinia использует концепцию независимых хранилищ (stores), где:

  • состояние изменяется напрямую;
  • отсутствуют мутации как отдельная сущность;
  • действия являются обычными функциями;
  • getters — вычисляемые свойства.

Такой подход ближе к нативной модели JavaScript и Composition API.

Подготовка к миграции

Перед началом миграции требуется:

  • обновить проект до Vue 3;
  • убедиться в отсутствии жёсткой зависимости от устаревших API Vuex;
  • выделить логические домены состояния (пользователь, корзина, настройки и т.д.);
  • зафиксировать текущее поведение приложения тестами или документацией.

Миграция возможна поэтапно, без полного отказа от Vuex на старте.

Установка и инициализация Pinia

Pinia подключается как плагин Vue-приложения и не требует сложной конфигурации:

import { createPinia } from 'pinia'

const pinia = createPinia()
app.use(pinia)

Pinia поддерживает devtools, SSR и динамическое создание хранилищ.

Перенос состояния (state)

Vuex:

state: () => ({
  count: 0
})

Pinia:

state: () => ({
  count: 0
})

Синтаксис практически идентичен, но состояние в Pinia становится реактивным без дополнительных обёрток.

Перенос getters

Vuex:

getters: {
  doubleCount: state => state.count * 2
}

Pinia:

getters: {
  doubleCount: state => state.count * 2
}

В Pinia getters могут использовать this, что упрощает композицию логики:

doubleCount() {
  return this.count * 2
}

Перенос mutations и actions

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

Vuex-модули преобразуются в отдельные stores Pinia. Пространства имён больше не требуются, так как каждый store изолирован.

Vuex:

modules: {
  user,
  cart
}

Pinia:

useUserStore()
useCartStore()

Такой подход улучшает читаемость и повторное использование логики.

Совместное использование Vuex и Pinia

Pinia может быть внедрена параллельно с Vuex. Это позволяет:

  • мигрировать функциональность по частям;
  • снизить риски;
  • постепенно переписывать модули.

Компоненты могут одновременно использовать оба хранилища без конфликтов.

Работа с SSR и Nuxt

Pinia официально поддерживается в Nuxt 3 и полностью интегрирована в SSR. Состояние корректно сериализуется и гидратируется без дополнительной логики, в отличие от Vuex, где часто требовалась ручная настройка.

Devtools и отладка

Pinia использует Vue Devtools и предоставляет:

  • таймлайн изменений;
  • инспекцию состояния;
  • поддержку hot module replacement.

История действий отображается как обычные вызовы функций, что упрощает анализ.

Итоги архитектурных изменений

Миграция с Vuex на Pinia приводит к:

  • уменьшению объёма кода;
  • улучшению читаемости;
  • нативной интеграции с Composition API;
  • более простой типизации;
  • гибкой архитектуре без глобального монолита состояния.

Pinia не является прямой копией Vuex, а представляет собой эволюцию подхода к управлению состоянием во Vue-приложениях.