Skip to content
← Todas las preguntas
🌱 Principiante

¿Qué es Pinia y en qué se diferencia de Vuex?

📦 Gestión de estado🍍 Pinia🗃️ Vuex

Pinia es la librería oficial de gestión de estado para Vue 3. Reemplaza a Vuex. El equipo de Vue la creó porque el diseño de Vuex (mutations, API basada en strings, módulos complejos) no encajaba bien con TypeScript y la Composition API.

Por qué Pinia reemplazó a Vuex

Vuex tiene tres puntos de dolor que Pinia elimina:

1. Las mutations desaparecen. En Vuex, no puedes cambiar el estado directamente. Tienes que escribir una mutation (síncrona) y hacer commit por nombre. Pinia permite que las actions cambien el estado directamente, porque el sistema de reactividad de Vue 3 rastrea los cambios automáticamente a través de DevTools sin necesitar una capa de mutations separada.

2. Inferencia completa de TypeScript. Vuex depende de claves string (commit('SET_USER'), dispatch('fetchUser'), getters.userName). Un typo en cualquiera de esos strings es un bug en runtime, no un error de compilación. Los stores de Pinia son objetos planos; tu IDE conoce cada propiedad y método.

3. Sin módulos ni namespacing. Vuex tiene un store global, dividido en módulos con namespace (store.commit('cart/ADD_ITEM')). Los stores de Pinia son independientes, cada uno es su propio defineStore(), importado directamente donde se necesite.

Comparación lado a lado

ts
// Vuex: mutations requeridas, basado en strings
store.commit('SET_COUNT', 5)
store.dispatch('fetchUsers')
store.getters.activeUsers

// Pinia: directo, type-safe
counterStore.count = 5
await userStore.fetchUsers()
userStore.activeUsers

Definiendo un 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)
  )

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

  async function checkout() {
    await api.checkout(items.value)
    items.value = []
  }

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

Esto usa la sintaxis de Composition API (función setup). También hay una sintaxis Options con propiedades state, getters y actions. Mismo resultado, diferente estilo.

Usándolo en un componente

vue
<script setup lang="ts">
import { useCartStore } from '@/stores/cart'

const cart = useCartStore()
</script>

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

Sin commit, sin dispatch, sin mapGetters. Solo importa el store y úsalo.

Tabla de diferencias clave

AspectoVuexPinia
MutationsRequeridas (síncronas)No existen
TypeScriptLimitado, API basada en stringsInferencia completa, type-safe
Estructura del storeUn store, módulos con namespaceStores independientes
DevToolsSí (time-travel, edición de estado)
SSRRequiere configuración cuidadosaSoporte integrado
Tamaño del bundle~6kb~1kb

Ver también: ¿Cómo funciona Vuex? · ¿Cómo funciona Pinia internamente? · ¿Cómo migrarías un módulo de Vuex a Pinia?

Referencias

Publicado bajo la licencia MIT.