El framework Vue para JavaScript se ha hecho popular para construir interfaces de usuario y aplicaciones de una sola página (SPA, single-page applications). Para garantizar que tus aplicaciones de gran tamaño funcionen de forma óptima, necesitas conocer a fondo la gestión de estados, es decir, el proceso de gestionar y centralizar los datos reactivos (estado) de una aplicación en varios componentes.

En Vue, la gestión del estado se ha basado durante mucho tiempo en Vuex, una biblioteca con un store centralizado para todos los componentes de una aplicación. Sin embargo, los recientes avances en el ecosistema Vue han dado lugar al sucesor de Vuex, Pinia.

Pinia ofrece un enfoque de gestión más ligero, modular e intuitivo. Se integra a la perfección con el sistema de reactividad y la API de Composición de Vue, facilitando a los desarrolladores la gestión y el acceso al estado compartido de forma escalable y mantenible.

Preparando el escenario: Pinia frente a Vuex

Como biblioteca de referencia para la gestión del estado en aplicaciones Vue, Vuex proporcionaba un store centralizado para todos los componentes de una aplicación. Sin embargo, con el avance de Vue, Pinia representa una solución más moderna. Exploremos en qué se diferencia de Vuex.

  • Diferencias en la API — La API de Composición de Pinia ofrece una API más fundamental e intuitiva que Vuex, lo que facilita la gestión del estado de la aplicación. Además, su estructura se parece mucho a la API de Opciones de Vue, familiar para la mayoría de los desarrolladores de Vue.
  • Soporte de tipado —  Históricamente, muchos desarrolladores de Vue han tenido problemas con el limitado soporte de tipos de Vuex. En cambio, Pinia es una biblioteca de gestión de estados totalmente tipada que elimina estas preocupaciones. Su seguridad de tipo ayuda a evitar posibles errores en tiempo de ejecución, contribuye a la legibilidad del código y facilita unas capacidades de escalado más fluidas.
  • Sistema de reactividad — Ambas bibliotecas aprovechan el sistema de reactividad de Vue, pero el enfoque de Pinia se ajusta más a la API de composición de Vue 3. Aunque la API de reactividad es potente, la gestión de estados complejos en aplicaciones grandes puede ser un reto. Afortunadamente, la arquitectura sencilla y flexible de Pinia facilita la gestión de estados en tus aplicaciones Vue 3. El patrón de store de Pinia te permite definir un store para gestionar una parte específica del estado de la aplicación, simplificando su organización y compartiéndolo entre componentes.
  • Naturaleza ligera — Con sólo 1 KB, Pinia se integra perfectamente en tu entorno de desarrollo, y su naturaleza ligera puede mejorar el rendimiento y los tiempos de carga de tu aplicación.

Cómo configurar un proyecto Vue con Pinia

Para integrar Pinia en un proyecto Vue, inicializa tu proyecto con Vue CLI o Vite. Tras la inicialización del proyecto, puedes instalar Pinia mediante npm o yarn como dependencia.

  1. Crea un nuevo proyecto Vue utilizando Vue CLI o Vite. A continuación, sigue las indicaciones para configurar tu proyecto.
    // Using Vue CLI
    vue create my-vue-ap
    // Using Vite
    npm create vite@latest my-vue-app -- --template vue
  2. Cambia tu directorio a la carpeta del proyecto recién creado:
    cd my-vue-app
  3. Instala Pinia como dependencia en tu proyecto.
    // Using npm
    npm install pinia
    // Using yarn
    yarn add pinia
  4. En tu archivo de entrada principal (normalmente main.js o main.ts), importa Pinia y dile a Vue que lo utilice:
    import { createApp } from 'vue';
    import { createPinia } from 'pinia';
    import App from './App.vue';
    
    const app = createApp(App);
    
    app.use(createPinia());
    app.mount('#app');

    Con Pinia instalado y configurado en tu proyecto Vue, estás listo para definir y utilizar stores para la gestión de estados.

Cómo crear un store en Pinia

El store es la columna vertebral de la gestión de estados en tu aplicación Vue potenciada con Pinia. Te ayuda a gestionar los datos de toda la aplicación de forma cohesionada y coordinada. El store es el lugar donde defines, guardas y gestionas los datos que compartirán los distintos componentes de tu aplicación.

Esta centralización es fundamental, ya que estructura y organiza los cambios de estado de tu aplicación, haciendo que el flujo de datos sea más predecible y fácil de depurar.

Además, un store en Pinia hace algo más que guardar el estado: Las funcionalidades incluidas en Pinia te permiten actualizar el estado mediante acciones y calcular estados derivados mediante getters. Estas funciones integradas contribuyen a un código base más eficiente y fácil de mantener.

El siguiente ejemplo ilustra la creación de un store básido de Pinia en el archivo src/store.js de un proyecto.

import { defineStore } from 'pinia';
export const useStore = defineStore('main', {
    state: () => ({
        count: 0,
    }),
    actions: {
        increment() {
            this.count++;
        },
    },
    getters: {
        doubleCount: (state) => state.count * 2,
    },
});

Cómo acceder al estado del store en los componentes

En comparación con Vuex, el enfoque de Pinia respecto al acceso y la gestión del estado es más intuitivo, especialmente si estás familiarizado con la API de composición de Vue 3. Esta API es un conjunto de varias que permiten incluir lógica reactiva y componible en tus componentes.

Considera el siguiente código.

<template>
	<div>{{ store.count }}</div>
</template>

<script>>
import { useStore } from './store';

export default {
	setup() {
	const store = useStore();
		return { store };
	},
}
</script>

En el fragmento anterior, la etiqueta <template> contiene el marcado HTML definido de tu componente. Para mostrar el valor de la propiedad count del store Pinia, utilizas la sintaxis de enlace de datos de Vue, expresada como {{ count }}.

La función useStore proporciona acceso al store Pinia, por lo que puedes importarla desde store.js utilizando import { useStore } from './store';.

Una característica de la API de composición de Vue 3, la función setup define el estado reactivo y la lógica de tu componente. Dentro de la función, llamas a useStore() para acceder al store Pinia.

A continuación, const count = store.count accede a la propiedad count del store, haciéndola disponible en el componente.

Por último, setup devuelve el count, permitiendo que la plantilla lo renderice. El sistema de reactividad de Vue significa que la plantilla de tu componente actualizará el valor de count siempre que cambie en el store.

A continuación se muestra una captura de pantalla de la salida.

Captura de pantalla de la página de inicio de la aplicación de demostración de Pinia Store
Captura de pantalla de la plantilla Pinia Store Demo cargada en un navegador.

Este ejemplo ilustra las ventajas de Pinia:

  • Simplicidad — Pinia permite acceder directamente al estado del store sin funciones de mapeo. En cambio, Vuex necesita mapState (o ayudantes similares) para lograr el mismo acceso.
  • Acceso directo al store — Pinia te permite acceder directamente a las propiedades de estado (como store.count), lo que hace que tu código sea más legible y comprensible. Mientras tanto, Vuex a menudo requiere getters para acceder incluso a propiedades fundamentales, añadiendo complejidad que disminuye la legibilidad.
  • Compatibilidad con la API de Composición — Como demuestra el método de configuración, la integración de Pinia con la API de Composición se alinea especialmente bien con el desarrollo moderno de Vue, proporcionando una experiencia de programación más uniforme.

Cómo modificar el estado con Pinia

En Pinia, puedes modificar el estado de un store mediante acciones, que son más flexibles que las mutaciones de Vuex. Considera la siguiente llamada a una función, que incrementa la propiedad count del estado:

store.increment(); // Increments the count

Por otro lado, un equivalente en Vuex implica definir una mutación además de al menos una acción:

mutations: {
	increment(state) {
	state.count++;
	},
},
actions: {
	increment({ commit }) {
	commit('increment');
	},
}

La acción Pinia y su código equivalente Vuex ejemplifican una diferencia crucial entre la complejidad del código de las bibliotecas. Exploremos más a fondo estas diferencias:

  • Mutación de estado directa frente a indirecta — Como demuestra la acción increment, las acciones Pinia mutan directamente el estado del store. En Vuex, sólo puedes cambiar el estado mediante mutaciones, que tienes que hacer commit con las acciones. Esta separación de procesos garantiza que tus cambios de estado sean rastreables, pero es más compleja y rígida que las acciones en Pinia.
  • Operaciones asíncronas frente a síncronas — Mientras que las mutaciones Vuex son siempre síncronas y no pueden contener procesos asíncronos, las acciones Pinia pueden contener código síncrono y asíncrono. Como resultado, puedes realizar llamadas a la API u otras operaciones asíncronas directamente dentro de las acciones, lo que hace que el código base sea más ágil y conciso.
  • Sintaxis simplificada — Vuex a menudo requiere definir mutaciones y llamar a acciones para realizarlas. Pinia elimina esta necesidad. La posibilidad de mutar el estado dentro de las acciones reduce el código repetitivo y hace que el código existente sea más sencillo. En Vuex, las actualizaciones básicas de estado requieren definir una acción y una mutación, incluso si la acción se limita a hacer commit de la mutación.

La transición de Vuex a Pinia

La transición a Pinia puede proporcionar numerosas ventajas en cuanto a simplicidad, flexibilidad y facilidad de mantenimiento, pero requiere una planificación y consideración cuidadosas para garantizar una implementación satisfactoria.

Antes de hacer el cambio, asegúrate de:

  1. Familiarizarte con las diferencias entre la arquitectura, los patrones de gestión de estados y las API de Pinia y Vuex. Comprender estas diferencias es crucial para refactorizar eficazmente tu código y aprovechar al máximo las características de Pinia.
  2. Analizar y refactorizar tu estado, acciones, mutaciones y getters de Vuex para que encajen en la estructura de Pinia. Recuerda que en Pinia defines el estado como una función. Puedes mutar estados directamente con acciones y puedes implementar getters más fácilmente.
  3. Planificar cómo realizar la transición de los módulos de tu store Vuex. Pinia no utiliza módulos del mismo modo que Vuex, pero aún así puedes estructurar tus stores para que sirvan a propósitos similares.
  4. Aprovecha la compatibilidad mejorada de Pinia con TypeScript. Si tu proyecto utiliza TypeScript, considera las capacidades mejoradas de inferencia de tipos y tipado de Pinia para mejorar la seguridad de tipos y la experiencia del desarrollador.
  5. Revisa tus estrategias de pruebas para adaptarlas a los cambios en la gestión de estados. Este proceso podría implicar la actualización de cómo simulas stores o acciones en tus pruebas unitarias y de integración.
  6. Considera cómo afecta la transición a la estructura y organización de tu proyecto. Ten en cuenta factores como las convenciones de nomenclatura y cómo importas y utilizas los stores en los distintos componentes.
  7. Asegúrate de la compatibilidad con otras bibliotecas. Comprueba si hay actualizaciones necesarias o cambios en las dependencias a los que pueda afectar el cambio.
  8. Evalúa cualquier cambio en el rendimiento. Pinia suele ser más ligero que Vuex, pero sigue supervisando el rendimiento de tu aplicación durante y después de la transición para asegurarte de que no haya problemas.

Convertir un store de Vuex a Pinia implica varios pasos para adaptarse a las diferencias en sus estructuras y API. Considera el store de Pinia anterior.

El mismo store en un archivo store.js de Vuex tiene el siguiente aspecto.

import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);

export default new Vuex.Store({
    state: {
        count: 0,
    },
    mutations: {
        increment(state) {
            state.count++;
        },
    },
    actions: {
        increment(context) {
            context.commit('increment');
        },
    },
    getters: {
        doubleCount(state) {
            return state.count * 2;
        },
    },
});

Al igual que el store Pinia anterior, este ejemplo Vuex contiene un objeto state con una única propiedad count inicializada a 0.

El objeto mutations contiene métodos para mutar directamente el estado, mientras que los métodos del objeto actions consignan la mutación increment.

A continuación, el objeto getters contiene el método doubleCount, que multiplica el estado count por 2 y devuelve el resultado.

Como demuestra este código, implementar un store en Pinia implica varias diferencias notables con Vuex:

  • Inicialización — Pinia no requiere Vue.use().
  • Estructura — En Pinia, el estado es una función que devuelve un objeto, lo que permite una mejor compatibilidad con TypeScript y reactividad.
  • Acciones — Las acciones en Pinia son métodos que mutan directamente el estado sin necesidad de mutaciones, simplificando el código.
  • Getters — Aunque similares a Vuex, los Getters en Pinia se definen dentro de la definición del store y pueden acceder directamente al estado.

Cómo utilizar el store en los componentes

Con Vuex, podrías utilizar el store de la siguiente manera:

<template>
	<div>{{ doubleCount }}</div>
	<button @click="increment">Increment</button>
</template>

<script>
import { mapGetters, mapActions } from 'vuex';

export default {
	computed: {
	...mapGetters(['doubleCount']),
	},
	methods: {
	...mapActions(['increment']),
	},
};
</script>

Para Pinia, el uso se convierte en:

<template>
	<div>{{ store.doubleCount }}</div>
	<button> @click="store.increment">Increment</button>
</template>

<script>>
import { useStore } from '/src/store';

export default {
	setup() {
	const store = useStore();
	return {
		store,
	};
	},
};
</script>
Captura de pantalla de la página de aterrizaje de la Demo del Store de Pinia en diferentes incrementos: 0, 2 y 4.
Conversiones de store Pinia.

Este ejemplo incluye una conversión básica. Para stores Vuex más complejos, especialmente los que utilizan módulos, la conversión implicaría una reestructuración más detallada para alinearse con la arquitectura de Pinia.

Cómo desplegar tu aplicación Vue

Antes de desplegar, regístrate para una prueba gratuita del servicio de Alojamiento de Aplicaciones de Kinsta. Desplegarás la aplicación con la ayuda de un archivo Dockerfile.

Crea un Dockerfile en la raíz de tu proyecto y pega el siguiente contenido:

FROM node:latest
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY ./ .
CMD ["npm", "run", "start"]

Este código indica al motor Docker de Kinsta que instale Node.js (FROM node:latest), cree el directorio de trabajo (WORKDIR /app), instale los módulos node desde el archivo package.json (RUN npm install) y establezca el comando start (CMD ["npm", "run", "start"]) que se invocará cuando se inicie la aplicación Vue. Los comandos COPY copian los archivos o directorios especificados al directorio de trabajo.

Después de eso, envía tu código a tu proveedor Git preferido (Bitbucket, GitHub o GitLab). Una vez que tu repositorio esté listo, sigue estos pasos para desplegar tu aplicación en Kinsta:

  1. Inicia sesión o crea una cuenta para ver tu panel MyKinsta.
  2. Autoriza a Kinsta con tu proveedor de Git.
  3. Selecciona Aplicación en la barra lateral izquierda y haz clic en el botón Añadir Aplicación.
  4. En el modal que aparece, elige el repositorio que quieres desplegar. Si tienes varias ramas, puedes seleccionar la rama deseada y dar un nombre a tu aplicación.
  5. Selecciona una de las ubicaciones de centros de datos disponibles.
  6. Elige tu entorno de construcción y selecciona Utilizar Dockerfile para configurar la imagen del contenedor.
  7. Si tu Dockerfile no está en la raíz de tu repositorio, utiliza Context para indicar su ruta y haz clic en Continuar.
  8. Puedes dejar vacía la entrada Comando de inicio. Kinsta utiliza npm start para iniciar tu aplicación.
  9. Selecciona el tamaño del pod y el número de instancias más adecuados para tu aplicación y haz clic en Continuar.
  10. Rellena los datos de tu tarjeta de crédito y haz clic en Crear aplicación.

Como alternativa al alojamiento de aplicaciones, puedes optar por desplegar tu aplicación Vue como un sitio estático con el alojamiento de sitios estáticos de Kinsta de forma gratuita.

Resumen

La transición de Vuex a Pinia marca una evolución significativa en la gestión de estados dentro del ecosistema Vue. La simplicidad de Pinia, su compatibilidad mejorada con TypeScript y su alineación con la API de composición de Vue 3 la convierten en una opción convincente para las aplicaciones Vue modernas.

Cuando estés listo para alojar tu aplicación Vue con Kinsta, podrás acceder a una infraestructura rápida, segura y fiable. Regístrate en Kinsta y utiliza nuestro servicio de alojamiento de aplicaciones.

Jeremy Holcombe Kinsta

Editor de Contenidos y Marketing en Kinsta, Desarrollador Web de WordPress y Redactor de Contenidos. Aparte de todo lo relacionado con WordPress, me gusta la playa, el golf y el cine. También tengo problemas con la gente alta ;).