# Stato condiviso con Pinia: store che non si duplicano

Pinia tiene lo stato fuori dai componenti: uno store per dominio, uno store setup, storeToRefs per la reattività e una istanza per richiesta in SSR.

> Pagina: https://ui.eneawork.it/blog/vue-3-pinia-store
> Markdown: https://ui.eneawork.it/blog/vue-3-pinia-store.md

*2026-11-01*

Lo stato condiviso con Pinia vive in uno store importabile, non in un provide/inject: il componente legge lo store e non sa chi altro lo sta usando. Uno store per dominio, non uno per componente.

## Uno store, un dominio

Il primo argomento di defineStore è l’id: è la chiave con cui gli strumenti di sviluppo e i plugin di persistenza riconoscono lo store. Due store con lo stesso id sono lo stesso store, anche se li dichiari in file diversi.

npm install pinia

// stores/cart.ts import { computed, ref } from "vue"; import { defineStore } from "pinia"; export type CartItem = { id: string; qty: number; price: number }; export const useCart = defineStore("cart", () => { const items = ref([]); const count = computed(() => items.value.reduce((n, i) => n + i.qty, 0)); const total = computed(() => items.value.reduce((n, i) => n + i.qty * i.price, 0)); function add(item: CartItem) { const found = items.value.find((i) => i.id === item.id); if (found) found.qty += item.qty; else items.value.push({ ...item }); } function clear() { items.value = []; } return { items, count, total, add, clear }; });

Lo store setup è una funzione: i ref diventano stato, i computed diventano getter, le funzioni diventano azioni. Non c’è un livello di mutation da scrivere: l’azione modifica lo stato e basta, e lo strumento di sviluppo registra la chiamata.

// main.ts import { createApp } from "vue"; import { createPinia } from "pinia"; import App from "./App.vue"; createApp(App).use(createPinia()).mount("#app");

## storeToRefs: la riga che tiene la reattività

Destrutturare lo store copia i valori e interrompe gli aggiornamenti. storeToRefs restituisce ref collegate per stato e getter; le azioni si chiamano sullo store, non si destrutturano, perché perdono il contesto.

import { storeToRefs } from "pinia"; import { useCart } from "@/stores/cart"; const cart = useCart(); const { count, total } = storeToRefs(cart); Cart ({{ count }}) — {{ total.toFixed(2) }}

## SSR: una istanza per richiesta

Sul server un modulo importato è condiviso da tutte le richieste. Se chiami createPinia() a livello di modulo, il carrello di un visitatore finisce nella pagina di un altro: l’istanza va creata dentro la funzione che costruisce l’app, una volta per richiesta.

Misurato il 1 novembre 2026: il catalogo conta 1.556 blocchi in 99 categorie; 20 stanno in dashboard, 15 in login e 3 in chat, tre categorie in cui lo stato attraversa più schermate (1 novembre 2026). Metodo: conteggio del campo categories di data/blocks.json con uno script Node, sul repository EneUI.

## Dove lo store si rompe

## Il limite da mettere in conto

Pinia non è un database: non deduplica le richieste, non sincronizza due schede e non risolve i conflitti. Se due componenti scrivono lo stesso campo, vince l’ultima azione. La persistenza è un plugin da configurare e testare, non una promessa del framework.

I componenti che leggono lo store sono già pronti: Vuetify, shadcn-vue e il blocco dashboard portano markup e stati, non lo stato. La base è in Composition API; il caso in cui la reattività si perde è in props che non si aggiornano, il confronto in Vue vs React.

## FAQ

### Uno store per componente o uno per dominio?

Uno per dominio. Lo store descrive un dato condiviso, come carrello o sessione; crearlo per componente riporta lo stato dentro l’albero e perde il vantaggio.

### Meglio store setup o store a opzioni?

Store setup se usi già la Composition API e vuoi chiamare composable dentro lo store. Lo store a opzioni resta più leggibile per chi arriva da Vuex e vuole reset automatico.

### Perché il contatore non si aggiorna nel template?

Perché hai destrutturato lo store senza storeToRefs e hai copiato il numero. Tieni lo store intero oppure usa storeToRefs per stato e getter.

### Come faccio la persistenza?

Con un plugin come pinia-plugin-persistedstate, scegliendo i campi da salvare. La persistenza non è nel core e va trattata come integrazione da testare.

### Lo store funziona in SSR?

Sì, a una condizione: una istanza Pinia per richiesta. Se crei l’istanza una volta a livello di modulo, lo stato di un visitatore arriva a un altro.
