Nov 28, 2025

Pinia : 5 pratiques essentielles

Découvrez 5 règles d’or pour garder vos stores Pinia lisibles, testables et scalables : découpage par responsabilité, getters plutôt que duplication, actions métier claires et plugins pour la technique.

Le problème avec la gestion d'état

Au début, la gestion d'état semble simple.

Toujours.

Quelques variables, deux ou trois actions... et tout roule. Mais ton projet grossit. Tu ajoutes de la logique métier, des appels API, du multi-tenant, des dashboards, du offline...

Et là, ton store.ts devient une pelote de laine géante. Un sac de nœuds. Et un terrain miné.

C'est là que tu réalises :

La gestion d'état n'est pas un détail technique. C'est un choix architectural.

Aujourd'hui, je bosse systématiquement avec Pinia sur les projets complexes (CRM, SaaS, dashboards, e-commerce headless). Et j'ai identifié 5 règles d'or qui m'évitent bien des migraines.

1. Découpe tôt. Sinon, tu souffriras tard

Beaucoup font l'erreur classique :

"Un store = une feature."

Mais une feature grossit vite. Et tout explose.

Ce que je conseille : crée un store par responsabilité.

// Trop vague, trop large
useAppStore()

// Plus clair, plus durable
useAuthStore()
useLeadStore()
useUiStore()
useSettingsStore()

Mon retour terrain : Un store "fourre-tout" devient vite un cauchemar. En séparant clairement tes responsabilités dès le départ, tu gagnes en lisibilité, testabilité et évolutivité.

2. Ne stocke jamais ce que tu peux calculer

Règle simple, mais vitale : 1 seule source de vérité.

Si une donnée peut être dérivée du state, utilise un getter.

getCartTotal: state => state.items.reduce((t, i) => t + i.price, 0)

Si tu dupliques l'info, un jour ou l'autre... tu chasses un bug fantôme.

"Pourquoi le total est bon ici... mais pas là ?"

3. Écris des actions qui racontent une histoire

Ne saucissonne pas tes workflows dans 3 actions techniques à appeler "à la main".

Crée une action métier, qui reflète une intention forte :

async function finalizeLead(id: number) {
  await validateLead(id)
  await sendNotification(id)
  await refreshLeadList()
}

Tu passes d'un mindset dev à un mindset produit. Tu écris en workflows. Et tu réduis les oublis.

4. Délègue ce qui ne relève pas du métier

Logs, persistance, tracking, analytics...

Ça ne devrait jamais polluer ton store. Utilise des plugins. Ou une couche technique externe.

defineStore('settings', {
  persist: true,
  state: () => ({ theme: 'dark' }),
})

Sur un projet avec espace admin + public, j'ai même séparé state métier et state technique dans deux layers Nuxt. Résultat : plus modulaire, plus clair, plus scalable.

5. Charge intelligemment. Tu gagnes des ms ET des users

Deux réflexes simples, mais game-changers :

Lance tes requêtes en parallèle

const [user, leads] = await Promise.all([getUser(), getLeads()])

Update ton state une seule fois Finis les flashs de UI ou les états intermédiaires bancals.

Résumé express

Mauvais réflexeBonne pratique
1 store géantStores par responsabilité
Données dupliquéesGetters & single source of truth
Actions techniquesActions métier
Logique globale dans storePlugins / couches externes
Requêtes en sérieFetch parallèle + update unitaire

Ce que beaucoup sous-estiment

"La gestion d'état, c'est pour plus tard."

Non. Plus tard, c'est quand ton projet crashe sur sa propre complexité.

Une mauvaise architecture de store, ça t'explose à la figure en prod. Et quand t'es en équipe ? Ton store devient un point de friction constant.

Avant de coder le moindre composant

Prends 1h de réflexion. Pose-toi ces questions :

  • Qui gère quoi ?
  • Quelles données sont globales ? Lesquelles sont locales ?
  • Où mettre la logique métier ?
  • Qu'est-ce qui doit survivre à un refresh ?

Cette heure-là, elle te fait économiser des jours. Voire des semaines.

Bonus : mon setup type avec Pinia + Nuxt

export const useLeadStore = defineStore('leads', {
  state: () => ({
    list: [] as Lead[],
    isLoading: false,
  }),

  getters: {
    completed: state => state.list.filter(l => l.status === 'done'),
  },

  actions: {
    async fetch() {
      this.isLoading = true
      this.list = await $api.get('/leads')
      this.isLoading = false
    },

    async processLead(id: number) {
      await this.updateLead(id, { status: 'processing' })
      await this.fetch()
    },
  },
})

Conclusion

Bien utiliser Pinia, ce n'est pas "savoir créer un store". C'est savoir construire un système.

Un système qui supporte la complexité d'un produit, pas juste d'une UI.

En tant que dev, ça t'apprend à mieux penser tes architectures. En tant que freelance, ça t'aide à livrer des projets solides, scalables, et durables.

Jordan Bastin
© 2025 Jordan Bastin.