Skip to content
← Todas las preguntas
🔥 Avanzado

¿Cómo migrarías un módulo de Vuex a Pinia?

📦 Gestión de estado🚚 Migración🍍 Pinia🗃️ Vuex

Migrar de Vuex a Pinia es mayormente mecánico: cada módulo de Vuex se convierte en su propio defineStore, las mutations desaparecen, y las llamadas basadas en strings commit/dispatch se convierten en llamadas directas a métodos. La parte difícil no es el store en sí. Es encontrar y actualizar cada componente que lo usa.

Conversión paso a paso

Antes: módulo de Vuex

ts
const cartModule = {
  namespaced: true,
  state: () => ({
    items: [] as CartItem[],
    total: 0
  }),
  getters: {
    itemCount: (state) => state.items.length
  },
  mutations: {
    ADD_ITEM(state, item: CartItem) {
      state.items.push(item)
      state.total += item.price
    },
    CLEAR(state) {
      state.items = []
      state.total = 0
    }
  },
  actions: {
    async checkout({ state, commit }) {
      await api.checkout(state.items)
      commit('CLEAR')
    }
  }
}

Después: store de Pinia

ts
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'

export const useCartStore = defineStore('cart', () => {
  const items = ref<CartItem[]>([])

  const total = computed(() =>
    items.value.reduce((sum, item) => sum + item.price, 0)
  )
  const itemCount = computed(() => items.value.length)

  function addItem(item: CartItem) {
    items.value.push(item)
  }

  function clear() {
    items.value = []
  }

  async function checkout() {
    await api.checkout(items.value)
    clear()
  }

  return { items, total, itemCount, addItem, clear, checkout }
})

Qué cambió

VuexPiniaPor qué
state.total (tracking manual)computed(() => ...)Computed deriva del estado, no necesita sincronización manual
Mutations (ADD_ITEM, CLEAR)Funciones normalesPinia rastrea cambios de estado a través de reactividad, no necesita capa de mutations
commit('CLEAR')clear()Llamada directa a función, type-safe
state, commit destructurados del contextoAcceso directo a refsTodo está en scope, sin objeto de contexto
Módulo con namespace (cart/ADD_ITEM)Store independienteSin strings de namespace, solo importa el store

Actualizando componentes

vue
<!-- Antes: Vuex -->
<script>
import { mapGetters, mapActions } from 'vuex'

export default {
  computed: {
    ...mapGetters('cart', ['itemCount'])
  },
  methods: {
    ...mapActions('cart', ['checkout'])
  }
}
</script>

<!-- Después: Pinia -->
<script setup lang="ts">
import { useCartStore } from '@/stores/cart'

const cart = useCartStore()
</script>

<template>
  <span>{{ cart.itemCount }} items</span>
  <button @click="cart.checkout()">Checkout</button>
</template>
Open in Vue Playground

Estrategia de migración para apps grandes

No reescribas todo de una vez. Pinia y Vuex pueden coexistir en la misma app:

  1. Instala Pinia junto a Vuex
  2. Migra un módulo a la vez, empezando por el más simple
  3. Actualiza todos los componentes que usan ese módulo
  4. Elimina el módulo de Vuex
  5. Repite hasta que no queden módulos de Vuex
  6. Desinstala Vuex

Ver también: ¿Qué es Pinia y en qué se diferencia de Vuex? · ¿Cómo funciona Vuex? · ¿Cómo funciona Pinia internamente?

Referencias

Publicado bajo la licencia MIT.