Aller au contenu principal

Comparaison des différences entre Vuex et Pinia

Comparaison des différences fondamentales entre Vuex et Pinia: design API, support TypeScript, modularisation et guide de migration.


1. Axes clefs pour l'entretien

  1. Différences fondamentales: Vuex impose les mutations, Pinia non; Pinia offre un meilleur support TypeScript; la modularisation est différente.
  2. Recommendation de choix: pour un nouveau projet Vue 3, privilégier Pinia; pour Vue 2, Vuex reste pertinent.
  3. Migration: étapes et points d'attention pour passer de Vuex à Pinia.

2. Vue d'ensemble des différences

CaractéristiqueVuexPinia
Version VueVue 2Vue 3
Complexité APIPlus verbeuse (mutations)Plus simple (sans mutations)
Support TypeScriptConfiguration supplémentaireSupport natif complet
ModularisationModules imbriquésStructure plate, stores indépendants
TaillePlus lourdePlus légère (environ 1KB)
Expérience devBonneMeilleure (HMR, Devtools)

3. Comparaison des APIs

3.1 Mutations vs Actions

Vuex: les mutations sont nécessaires pour modifier le state de façon synchrone.

// Vuex
export default createStore({
state: { count: 0 },
mutations: {
INCREMENT(state) {
state.count++;
},
},
actions: {
increment({ commit }) {
commit('INCREMENT');
},
},
});

Pinia: pas de mutations, on modifie le state directement dans actions.

// Pinia
export const useCounterStore = defineStore('counter', {
state: () => ({ count: 0 }),
actions: {
increment() {
this.count++; // modification directe
},
},
});

Différence clef:

  • Vuex: actions appellent mutations via commit.
  • Pinia: les actions modifient le state directement (sync/async).

3.2 Définition du state

Vuex: state peut être un objet ou une fonction.

state: {
count: 0,
}

Pinia: state doit être une fonction pour éviter le partage d'état entre instances.

state: () => ({
count: 0,
})

3.3 Getters

Vuex: les getters reçoivent (state, getters).

getters: {
doubleCount: (state) => state.count * 2,
doubleCountPlusOne: (state, getters) => getters.doubleCount + 1,
}

Pinia: les getters peuvent utiliser this pour accéder à d'autres getters.

getters: {
doubleCount: (state) => state.count * 2,
doubleCountPlusOne(): number {
return this.doubleCount + 1;
},
}

3.4 Utilisation dans les composants

Vuex: via mapState, mapGetters, mapActions.

computed: {
...mapState(['count']),
...mapGetters(['doubleCount']),
},
methods: {
...mapActions(['increment']),
}

Pinia: usage direct du store; storeToRefs pour conserver la réactivité.

const store = useCounterStore();
const { count, doubleCount } = storeToRefs(store);
const { increment } = store;

4. Différences de modularisation

4.1 Modules Vuex (imbriqués)

Vuex: modules imbriqués avec namespaced: true.

// stores/user.js
export default {
namespaced: true,
state: { name: 'John' },
mutations: {
SET_NAME(state, name) {
state.name = name;
},
},
};

// Utilisation dans un composant
this.$store.dispatch('user/SET_NAME', 'Jane');

4.2 Stores Pinia (plats)

Pinia: chaque store est indépendant, sans imbrication.

// stores/user.ts
export const useUserStore = defineStore('user', {
state: () => ({ name: 'John' }),
actions: {
setName(name: string) {
this.name = name;
},
},
});

// Utilisation dans un composant
const userStore = useUserStore();
userStore.setName('Jane');

Différence clef:

  • Vuex: préfixes de namespace nécessaires.
  • Pinia: API directe sans namespace préfixé.

5. Différences de support TypeScript

5.1 TypeScript avec Vuex

Vuex: demande plus de typage manuel.

// stores/types.ts
export interface State {
count: number;
user: { name: string; age: number };
}

// stores/index.ts
import { createStore, Store } from 'vuex';
import { State } from './types';

export default createStore<State>({
state: { count: 0, user: { name: 'John', age: 30 } },
});

// Utilisation dans un composant
const store = useStore<State>();

5.2 TypeScript avec Pinia

Pinia: inférence de types native et autocomplétion plus robuste.

// stores/counter.ts
export const useCounterStore = defineStore('counter', {
state: () => ({
count: 0,
user: { name: 'John', age: 30 },
}),
getters: {
doubleCount: (state) => state.count * 2, // type inféré automatiquement
},
actions: {
increment() {
this.count++; // inférence et autocomplétion complète
},
},
});

// Utilisation dans un composant
const store = useCounterStore();
store.count;
store.doubleCount;
store.increment();

Différence clef:

  • Vuex: plus de définitions manuelles, inférence limitée.
  • Pinia: inférence native plus fiable.

6. Guide de migration

6.1 Étapes de base

  1. Installer Pinia
npm install pinia
  1. Remplacer le store Vuex
// Ancien: Vuex
import { createStore } from 'vuex';
export default createStore({ ... });

// Nouveau: Pinia
import { createPinia } from 'pinia';
const pinia = createPinia();
app.use(pinia);
  1. Convertir les définitions de store
// Vuex
export default createStore({
state: { count: 0 },
mutations: {
INCREMENT(state) {
state.count++;
},
},
actions: {
increment({ commit }) {
commit('INCREMENT');
},
},
});

// Pinia
export const useCounterStore = defineStore('counter', {
state: () => ({ count: 0 }),
actions: {
increment() {
this.count++;
},
},
});
  1. Mettre à jour l'usage dans les composants
// Vuex
import { mapState, mapActions } from 'vuex';
computed: { ...mapState(['count']) },
methods: { ...mapActions(['increment']) },

// Pinia
import { storeToRefs } from 'pinia';
const store = useCounterStore();
const { count } = storeToRefs(store);
const { increment } = store;

6.2 Questions fréquentes lors de la migration

Question 1: que faire des modules Vuex?

// Vuex modules
modules: {
user: userModule,
product: productModule,
}

// Pinia: un store par module
// stores/user.ts
export const useUserStore = defineStore('user', { ... });

// stores/product.ts
export const useProductStore = defineStore('product', { ... });

Question 2: comment remplacer les namespaces?

// Vuex: préfixe de namespace
this.$store.dispatch('user/SET_NAME', 'John');

// Pinia: appel direct
const userStore = useUserStore();
userStore.setName('John');

7. Pourquoi Pinia n'a pas besoin de mutations?

Raisons:

  1. Système réactif de Vue 3

    • Vue 3 s'appuie sur Proxy et suit les modifications directement.
    • Le détour par mutations n'est plus nécessaire.
  2. API simplifiée

    • Moins de boilerplate.
    • Les actions couvrent les mises à jour sync et async.
  3. Meilleure expérience de dev

    • Moins de concepts à mémoriser.
    • Plus besoin de distinguer sans cesse commit et dispatch.

Exemple:

// Vuex: avec mutations
mutations: { SET_COUNT(state, count) { state.count = count; } },
actions: { setCount({ commit }, count) { commit('SET_COUNT', count); } },

// Pinia: modification directe
actions: { setCount(count) { this.count = count; } },

8. Comment choisir entre Vuex et Pinia?

Recommandations:

  1. Nouveau projet

    • Vue 3: Pinia recommandé
    • Vue 2: Vuex reste le choix naturel
  2. Projet existant

    • Vue 2 + Vuex: possible de rester sur Vuex, ou migrer plus tard
    • Vue 3 + Vuex: migration vers Pinia envisageable, pas obligatoire
  3. Besoins projet

    • Fort besoin TypeScript: Pinia
    • API plus lisible: Pinia
    • Équipe experte Vuex: continuer Vuex peut être pragmatique

Résumé:

  • Nouveau projet Vue 3: Pinia fortement recommandé
  • Projet Vue 2: Vuex
  • Projet Vue 3 existant avec Vuex: migration selon ROI, pas par réflexe

9. Synthèse pour entretien

9.1 Différences essentielles

Réponse possible:

Vuex et Pinia résolvent le même problème, mais Pinia simplifie fortement l'approche: pas de mutations, stores indépendants, meilleure inférence TypeScript, et une expérience de dev plus fluide dans Vue 3. Pour un nouveau projet Vue 3, je recommande Pinia.

Points clefs:

  • ✅ Complexité API
  • ✅ Qualité du support TypeScript
  • ✅ Stratégie de modularisation
  • ✅ Recommandation selon le contexte

9.2 Pourquoi pas de mutations dans Pinia?

Réponse possible:

Pinia s'appuie sur la réactivité de Vue 3 (Proxy), qui permet de suivre les changements de state directement. Cela réduit le boilerplate, simplifie l'API et rend le code plus lisible, tout en gardant les cas sync/async dans les actions.

Points clefs:

  • ✅ Réactivité de Vue 3
  • ✅ Simplification API
  • ✅ DX améliorée

10. Conclusion

Réponse possible:

La différence principale entre Vuex et Pinia tient au design API, à TypeScript et à la modularisation. Pinia est plus moderne pour Vue 3: moins de cérémonie, meilleure inférence, stores clairs. En migration, il faut retirer les mutations, convertir les modules en stores indépendants et mettre à jour l'accès composant avec storeToRefs + actions directes.

Points clefs:

  • ✅ Différences bien structurées
  • ✅ Conseils de choix
  • ✅ Étapes de migration
  • ✅ Retour d'expérience concret

Références