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.