Il framework Vue per JavaScript è diventato popolare per la creazione di interfacce utente e applicazioni a pagina singola (SPA). Per garantire che le applicazioni di grandi dimensioni funzionino in modo ottimale, è necessario comprendere bene la gestione dello stato, ovvero il processo di gestione e centralizzazione dei dati reattivi (stato) di un’applicazione tra più componenti.

In Vue, la gestione dello stato è stata a lungo affidata a Vuex, una libreria con un archivio centralizzato per tutti i componenti di un’applicazione. Tuttavia, i recenti progressi nell’ecosistema Vue hanno dato vita al successore di Vuex, Pinia.

Pinia offre un approccio di gestione più leggero, modulare e intuitivo. Si integra perfettamente con il sistema di reattività di Vue e con l’API Composition, rendendo semplice per gli sviluppatori gestire e accedere allo stato condiviso in modo scalabile e manutenibile.

Come si presenta la situazione: Pinia vs Vuex

Come libreria di riferimento per la gestione dello stato nelle applicazioni Vue, Vuex forniva uno store centralizzato per tutti i componenti di un’applicazione. Tuttavia, con il progresso di Vue, Pinia rappresenta una soluzione più moderna. Vediamo come si differenzia da Vuex.

  • Differenze API – L’API di composizione di Pinia offre un’API più essenziale e intuitiva rispetto a Vuex, rendendo più semplice la gestione dello stato dell’applicazione. Inoltre, la sua struttura assomiglia molto all’API Options di Vue, familiare alla maggior parte degli sviluppatori di Vue.
  • Supporto dei tipi – Storicamente, molti sviluppatori di Vue hanno avuto problemi con il limitato supporto dei tipi di Vuex. Al contrario, Pinia è una libreria per la gestione degli stati completamente tipizzata che elimina questi problemi. La sicurezza dei tipi aiuta a prevenire potenziali errori di runtime, contribuisce alla leggibilità del codice e facilita la scalabilità.
  • Sistema di reattività – Entrambe le librerie sfruttano il sistema di reattività di Vue, ma l’approccio di Pinia si allinea maggiormente con l’API Composition di Vue 3. Sebbene l’API di reattività sia potente, la gestione di stati complessi in applicazioni di grandi dimensioni può essere impegnativa. Fortunatamente, l’architettura semplice e flessibile di Pinia facilita la gestione degli stati nelle applicazioni Vue 3. Il pattern store di Pinia permette di definire uno store per la gestione di una porzione specifica dello stato dell’applicazione, semplificandone l’organizzazione e la condivisione tra i vari componenti.
  • Leggerezza – Con un peso di appena 1 KB, Pinia si integra perfettamente nell’ambiente di sviluppo e la sua leggerezza può migliorare le prestazioni e i tempi di caricamento delle applicazioni.

Come impostare un progetto Vue con Pinia

Per integrare Pinia in un progetto Vue, inizializziamo il progetto con Vue CLI o Vite. Dopo l’inizializzazione del progetto, possiamo installare Pinia come dipendenza tramite npm o yarn.

  1. Creiamo un nuovo progetto Vue utilizzando Vue CLI o Vite. Quindi, seguiamo le istruzioni per configurare il nostro progetto.
    // Using Vue CLI
    vue create my-vue-ap
    // Using Vite
    npm create vite@latest my-vue-app -- --template vue
  2. Cambiamo la directory nella cartella del progetto appena creato:
    cd my-vue-app
  3. Installiamo Pinia come dipendenza nel nostro progetto.
    // Using npm
    npm install pinia
    // Using yarn
    yarn add pinia
  4. Nel nostro file di inserimento principale (di solito main.js o main.ts), importiamo Pinia e diciamo a Vue di usarlo:
    import { createApp } from 'vue';
    import { createPinia } from 'pinia';
    import App from './App.vue';
    
    const app = createApp(App);
    
    app.use(createPinia());
    app.mount('#app');

    Dopo aver installato e configurato Pinia nel nostro progetto Vue, siamo pronti a definire e utilizzare gli store per la gestione degli stati.

Come creare uno store in Pinia

Lo store è la spina dorsale della gestione dello stato in un’applicazione Vue alimentata da Pinia. Aiuta a gestire i dati dell’applicazione in modo coeso e coordinato. Lo store è il luogo in cui definiamo, memorizziamo e gestiamo i dati da condividere tra i vari componenti dell’applicazione.

Questa centralizzazione è fondamentale perché struttura e organizza i cambiamenti di stato dell’applicazione, rendendo il flusso di dati più prevedibile e semplice da debuggare.

Inoltre, uno store in Pinia non si limita a contenere lo stato: le funzionalità incluse in Pinia permettono di aggiornare lo stato tramite azioni e di calcolare gli stati derivati tramite getter. Queste funzionalità integrate contribuiscono a rendere la base di codice più efficiente e manutenibile.

Il seguente esempio illustra la creazione di uno store Pinia di base nel file src/store.js di un progetto.

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

Come accedere allo stato dello store nei componenti

Rispetto a Vuex, l’approccio di Pinia all’accesso e alla gestione dello stato è più intuitivo, soprattutto se si ha familiarità con l’API Composition di Vue 3. Questa API è un insieme di funzioni che permettono di includere una logica reattiva e componibile. Questa API è un insieme di funzioni che consentono di includere una logica reattiva e componibile nei nostri componenti.

Consideriamo il seguente codice.

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

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

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

Nello snippet qui sopra, il tag <template> contiene il markup HTML definito del nostro componente. Per visualizzare il valore della proprietà count dallo store Pinia, utilizziamo la sintassi del data binding di Vue, espressa come {{ count }}.

La funzione useStore fornisce l’accesso allo store Pinia, quindi la importiamo da store.js usando import { useStore } from './store';.

Una caratteristica dell’API Composition di Vue 3, la funzione setup definisce lo stato e la logica reattiva del nostro componente. All’interno della funzione, chiamiamo useStore() per accedere allo store Pinia.

Successivamente, const count = store.count accede alla proprietà count dello store, rendendola disponibile nel componente.

Infine, setup restituisce la proprietà count, consentendo al template di eseguire il rendering. Il sistema di reattività di Vue significa che il template del nostro componente aggiornerà il valore di count ogni volta che cambia nello store.

Di seguito è riportata una schermata dell’output.

Schermata del modello Pinia Store Demo caricato in un browser
Schermata del modello Pinia Store Demo caricato in un browser.

Questo esempio illustra i vantaggi di Pinia:

  • Semplicità: Pinia permette di accedere direttamente allo stato dello store senza funzioni di mappatura. Al contrario, Vuex ha bisogno di mapState (o di aiutanti simili) per ottenere lo stesso accesso.
  • Accesso diretto allo store: Pinia permette di accedere direttamente alle proprietà dello stato (come store.count), rendendo il nostro codice più leggibile e comprensibile. Al contrario, Vuex spesso richiede dei getter per accedere anche alle proprietà fondamentali, aggiungendo complessità che diminuisce la leggibilità.
  • Compatibilità con le API di composizione: come dimostra il metodo di configurazione, l’integrazione di Pinia con le API di composizione si allinea particolarmente bene con lo sviluppo moderno di Vue, offrendo un’esperienza di codifica più uniforme.

Come modificare lo stato con Pinia

In Pinia, possiamo modificare lo stato di uno store utilizzando le azioni, che sono più flessibili delle mutazioni di Vuex. Consideriamo la seguente chiamata di funzione, che incrementa la proprietà count dello stato:

store.increment(); // Increments the count

D’altra parte, l’equivalente di Vuex prevede la definizione di una mutazione oltre ad almeno un’azione:

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

L’azione di Pinia e il suo codice equivalente di Vuex esemplificano una differenza cruciale tra la complessità del codice delle due librerie. Esploriamo ulteriormente queste differenze:

  • Mutazione diretta o indiretta dello stato: come dimostra l’azione increment, le azioni di Pinia modificano direttamente lo stato dello store. In Vuex, invece, è possibile cambiare lo stato solo utilizzando le mutazioni, che è necessario impegnare con le azioni. Questa separazione dei processi garantisce la tracciabilità delle modifiche allo stato, ma è più complessa e rigida rispetto alle azioni Pinia.
  • Operazioni asincrone e sincrone: mentre le mutazioni di Vuex sono sempre sincrone e non possono contenere processi asincroni, le azioni di Pinia possono contenere codice sincrono e asincrono. Di conseguenza, possiamo eseguire chiamate API o altre operazioni asincrone direttamente all’interno delle azioni, rendendo la base di codice più snella e concisa.
  • Sintassi semplificata: Vuex spesso richiede la definizione di mutazioni e la chiamata di azioni per eseguirle. Pinia elimina questa necessità. La possibilità di mutare lo stato all’interno delle azioni riduce il codice boilerplate e rende più semplice il codice esistente. In Vuex, gli aggiornamenti di base dello stato richiedono la definizione di un’azione e di una mutazione, anche se l’azione si limita a commettere la mutazione.

Il passaggio da Vuex a Pinia

Il passaggio a Pinia può offrire numerosi vantaggi in termini di semplicità, flessibilità e manutenibilità, ma richiede un’attenta pianificazione e considerazione per garantire un’implementazione di successo.

Prima di effettuare il passaggio, assicuratevi di:

  1. Familiarizzare con le differenze tra l’architettura di Pinia e Vuex, i modelli di gestione dello stato e le API. Comprendere queste differenze è fondamentale per rifattorizzare efficacemente il codice e sfruttare appieno le funzionalità di Pinia.
  2. Analizzare e rifattorizzare lo stato, le azioni, le mutazioni e i getter di Vuex per adattarli alla struttura di Pinia. Ricordate che in Pinia definite lo stato come una funzione. Potete mutare direttamente gli stati con le azioni, oltre a implementare i getter in modo più semplice.
  3. Pianificare la transizione dei moduli dello store Vuex. Pinia non utilizza i moduli come Vuex, ma è comunque possibile strutturare gli store in modo che servano a scopi simili.
  4. Sfruttare il supporto migliorato di Pinia per TypeScript. Se il progetto utilizza TypeScript, prendete in considerazione le funzionalità migliorate di Pinia per l’inferenza dei tipi e la tipizzazione per migliorare la sicurezza dei tipi e l’esperienza degli sviluppatori.
  5. Rivedere le strategie di testing per adattarle ai cambiamenti nella gestione degli stati. Questo processo potrebbe comportare l’aggiornamento delle modalità di simulazione di store o azioni nei test unitari e di integrazione.
  6. Considerare come la transizione influisce sulla struttura e sull’organizzazione del progetto. Tenete conto di fattori come le convenzioni di denominazione e il modo in cui importate e utilizzate gli store tra i vari componenti.
  7. Assicurare la compatibilità con le altre librerie. Controllate gli aggiornamenti necessari o le modifiche alle dipendenze che il passaggio potrebbe comportare.
  8. Valutare eventuali modifiche alle prestazioni. Pinia è generalmente più leggero di Vuex, ma continuate a monitorare le prestazioni dell’applicazione durante e dopo la transizione per assicurarvi che non ci siano problemi.

La conversione di uno store da Vuex a Pinia comporta diversi passaggi per tenere conto delle differenze nelle strutture e nelle API. Consideriamo lo store Pinia di prima.

Lo stesso store in un file store.js di Vuex appare come segue.

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;
        },
    },
});

Come per il precedente store Pinia, questo esempio Vuex contiene un oggetto state con una singola proprietà count inizializzata a 0.

L’oggetto mutations contiene metodi per mutare direttamente lo stato, mentre i metodi dell’oggetto actions impegnano la mutazione increment.

Quindi, l’oggetto getters contiene il metodo doubleCount, che moltiplica lo stato count per 2 e restituisce il risultato.

Come dimostra questo codice, l’implementazione di uno store in Pinia comporta diverse differenze evidenti rispetto a Vuex:

  • Inizializzazione – Pinia non richiede Vue.use().
  • Struttura – In Pinia, lo stato è una funzione che restituisce un oggetto, consentendo un migliore supporto di TypeScript e una maggiore reattività.
  • Azioni – Le azioni in Pinia sono metodi che modificano direttamente lo stato senza bisogno di mutazioni, semplificando il codice.
  • Getter – Sebbene siano simili a quelli di Vuex, i Getter di Pinia sono definiti all’interno della definizione dello store e possono accedere direttamente allo stato.

Come utilizzare lo store nei componenti

Con Vuex, potremmo utilizzare lo store in questo modo:

<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>

Per Pinia, l’utilizzo diventa:

<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>
Schermata della landing page del Pinia Store Demo con diversi incrementi: 0, 2 e 4.
Conversioni dello store Pinia.

Questo esempio riguarda una conversione di base. Per store Vuex più complessi, in particolare quelli che utilizzano moduli, la conversione comporterà una ristrutturazione più dettagliata per allinearsi all’architettura di Pinia.

Come distribuire un’applicazione Vue

Prima di procedere al deploy, create un account per accedere alla prova gratuita del servizio di Hosting di Applicazioni di Kinsta. L’applicazione verrà distribuita con l’aiuto di un file Docker.

Create un file Docker nella root del progetto e incollate i seguenti contenuti:

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

Questo codice istruisce il motore Docker di Kinsta a installare Node.js (FROM node:latest), a creare la directory di lavoro (WORKDIR /app), a installare i moduli node dal file package.json (RUN npm install) e a impostare il comando start (CMD ["npm", "run", "start"]) che verrà invocato all’avvio dell’applicazione Vue. I comandi COPY copiano i file o le directory specificate nella directory di lavoro.

Dopodiché, inviate il codice al provider Git che preferite (Bitbucket, GitHub o GitLab). Quando il repo sarà pronto, seguite questi passaggi per distribuire l’applicazione su Kinsta:

  1. Accedete o create un account per visualizzare la dashboard MyKinsta.
  2. Autorizzate Kinsta con il provider Git.
  3. Selezionate Applicazione nella barra laterale di sinistra e cliccate sul pulsante Aggiungi applicazione.
  4. Nella finestra di dialogo che appare, scegliete il repository che volete distribuire. Se avete più branch, potete selezionare il branch desiderato e dare un nome alla vostra applicazione.
  5. Selezionate uno dei data center disponibili.
  6. Scegliete l’ambiente di build e selezionate Usa il file Docker per impostare l’immagine del container.
  7. Se il Dockerfile non si trova nella root del repo, usate Context per indicare il suo percorso e cliccate su Continua.
  8. Potete lasciare vuota la voce Comando start. Kinsta utilizza npm start per avviare l’applicazione.
  9. Selezionate la dimensione del pod e il numero di istanze più adatto all’applicazione e cliccate su Continua.
  10. Inserite i dati della carta di credito e cliccate su Crea applicazione.

In alternativa all’Hosting di Applicazioni, potete scegliere di distribuire la vostra applicazione Vue come sito statico con l’Hosting di Siti Statici gratuito di Kinsta.

Riepilogo

Il passaggio da Vuex a Pinia segna un’evoluzione significativa nella gestione degli stati all’interno dell’ecosistema Vue. La semplicità di Pinia, il supporto migliorato di TypeScript e l’allineamento con l’API Composition di Vue 3 ne fanno una scelta convincente per le moderne applicazioni Vue.

Quando sarete pronti a ospitare la vostra applicazione Vue con Kinsta, potete accedere a un’infrastruttura veloce, sicura e affidabile. Create un account Kinsta e utilizzate subito il nostro servizio di Hosting di Applicazioni.

Jeremy Holcombe Kinsta

Content & Marketing Editor presso Kinsta, web developer di WordPress e content writer. Al di fuori di tutto ciò che riguarda WordPress, mi piacciono la spiaggia, il golf e il cinema. Ho anche i problemi di tutte le persone più alte della media ;).