Découvrez les mutations
Dans le chapitre précédent, nous avons appris à définir notre espace de stockage de données dans Vuex avec state
et des accesseurs, mais également à récupérer nos données avec des méthodes comme mapState
et mapGetters
. Dans ce chapitre, nous allons passer à l'étape suivante dans la gestion de notre data store : mettre à jour et modifier nos données dans Vuex avec les mutations.
Comme nous l'avons vu dans la structure initiale de store.js :
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
},
mutations: {
},
actions: {
}
})
La deuxième clé définie dans le store est appelée mutation. Comme son nom l'indique, elle contiendra un objet de toutes les propriétés responsables de modifications du state
.
Définissez une mutation
Si nous prenons l'exemple traditionnel du compteur, nous pouvons définir une mutation comme suit :
export default new Vuex.Store({
state: {
count: 0
},
mutations: {
INCREASE_COUNT(state) {
state.count += 1
}
},
actions: {
}
})
Par défaut, la mutation reçoit le state
en premier argument. Ce dernier peut ensuite être utilisé pour effectuer les modifications nécessaires. Dans l'exemple ci-dessus, nous ne faisons qu'incrémenter state.count
de 1.
Cependant, cette technique a ses limites car nous pourrions envisager de rendre la valeur incrémentée dynamique. Heureusement, les mutations peuvent prendre un deuxième argument : le paramètre payload.
export default new Vuex.Store({
state: {
count: 0
},
mutations: {
INCREASE_COUNT(state, payload) {
state.count += Number(payload)
}
},
actions: {
}
})
Dans l'exemple révisé, nous autorisons maintenant l'utilisateur à :
transmettre de combien nous voulons que
state.count
soit incrémentée ;fixer une valeur par défaut de 1, au cas où l'utilisateur oublie de transmettre une valeur :
convertir la valeur en nombre pour qu'elle ne s'ajoute pas comme chaîne de caractères par accident.
Actez une mutation
Lorsqu'il s'agit de modifier le state d'une application, il est essentiel que cela soit fait au bon moment. En d'autres termes, une attention et un soin particuliers sont accordés à ces événements, afin de s'assurer que toute erreur soit facilement identifiée. Par conséquent, plutôt que d'invoquer la mutation comme une fonction normale, nous utilisons une action spéciale : commit.
Lorsqu'une mutation est actée, l'action commit prend deux paramètres :
nom de la mutation ;
payload (facultatif).
this.$store.commit('INCREMENT_COUNT', 2)
Lorsqu'une mutation est actée, la modification est faite immédiatement. En d'autres termes, les mutations Vuex sont synchrones, ce qui signifie qu'il n'est par exemple pas possible de récupérer des données d'une API dans une mutation.
Bien sûr, vous vous demandez probablement de quelle manière il faudrait acter les mutations. Pour répondre à cette question, nous allons devoir parler des actions.
Découvrez les actions
Jusqu'à présent, nous avons appris que :
State
contient notre data store global ;les accesseurs (getters) servent de propriétés calculées à nos espaces de stockage de données ;
les mutations nous permettent de mettre à jour/modifier le state.
La dernière pièce du puzzle est les actions. Elles nous servent à coordonner la logique derrière les mutations. En d'autres termes, elles sont similaires à la propriété methods
dans une instance de Vue.
Définissez une action
Pour continuer avec notre exemple de compteur, nous pourrions définir notre action de la façon suivante :
export default new Vuex.Store({
state: {
count: 0
},
mutations: {
INCREASE_COUNT(state, amount = 1) {
state.count += Number(amount)
}
},
actions: {
incrementCount(context, amount) {
context.commit('INCREMENT_COUNT', amount)
}
}
})
Une action est composée d'un nom, du paramètre context
et d'un payload optionnel (comme pour les mutations). Dans l'exemple ci-dessus :
incrementCount
est le nom de l'action ;le paramètre
context
nous donne accès aux mêmes méthodes et propriétés dans l'instance du store Vuex (par exemple, commit, state, getters, etc.) ;amount
est le payload que nous devons transmettre à la mutation, afin qu'elle augmente de la bonne valeur.
Découvrez l'utilité des actions
Sur la base de l'exemple ci-dessus, vous vous demandez peut-être pourquoi ne pas simplement appeler la mutation directement. Mais que se passerait-il lorsqu'il faut diminuer le count
d'une certaine valeur ?
export default new Vuex.Store({
state: {
count: 0
},
mutations: {
INCREASE_COUNT(state, amount = 1) {
state.count += Number(amount)
},
DECREASE_COUNT(state, amount = 1) {
state.count -= Number(amount)
}
},
actions: {
incrementCount(context, amount) {
context.commit('INCREMENT_COUNT', amount)
}
}
})
Une certaine logique est nécessaire pour déterminer quand déclencher chaque mutation. Pour tenir compte de cela, rendons notre action générique de la manière suivante :
export default new Vuex.Store({
state: {
count: 0
},
mutations: {
INCREASE_COUNT(state, amount = 1) {
state.count += Number(amount)
},
DECREASE_COUNT(state, amount = 1) {
state.count -= Number(amount)
}
},
actions: {
updateCount(context, amount) {
if (amount >= 0) {
context.commit('INCREASE_COUNT', amount)
} else {
context.commit('DECREASE_COUNT', amount)
}
}
}
})
Pourquoi ne pas simplement réunir les mutations en une seule ?
Nous pourrions rendre la mutation générique à quelque chose comme CHANGE_COUNT
, mais en regardant l'historique, cela nous fournirait moins de détails, ce qui rend les choses plus difficiles à débugger. Par conséquent, il est préférable que les mutations gardent un seul usage. Laissez la logique aux actions.
De plus, comme le paramètre context
peut être utilisé pour accéder à de nombreuses propriétés différentes du store Vuex, vous allez découvrir une technique de codage courante qui est l'affectation par décomposition (desctructuring, en anglais). Elle est faite pour simplifier le code et le rendre plus facile à lire. Avec notre exemple, cela ressemblerait à ce qui suit :
export default new Vuex.Store({
state: {
count: 0
},
mutations: {
INCREASE_COUNT(state, amount = 1) {
state.count += Number(amount)
},
DECREASE_COUNT(state, amount = 1) {
state.count -= Number(amount)
}
},
actions: {
updateCount({ commit }, amount) {
if (amount >= 0) {
commit('INCREASE_COUNT', amount)
} else {
commit('DECREASE_COUNT', amount)
}
}
}
})
En plus de nous donner la liberté de déterminer la logique du moment où les mutations sont déclenchées, les actions
sont asynchrones. Cela signifie que vous ne pouvez appeler des API et acter des mutations qu'en cas de réussite. Ou en fonction de ce que vous souhaitez réaliser.
Maintenant que nous savons comment définir les actions, la question suivante se pose : comment les utiliser dans nos composants ?
Utilisez les actions dans les composants
Tout comme il existe un terme spécial pour invoquer les mutations (c'est-à-dire acter ou « commit »), il existe aussi un terme spécial pour les actions : propager (dispatch). En d'autres termes, vous envoyez l'action pour exécuter une tâche. Donc, si vous vouliez propager une action depuis votre composant, cela ressemblerait à ce qui suit :
<template>
<div>
<p>{{ count }}</p>
<button @click="sendUpdateCountAction">Increment</button>
</div>
</template>
<script>
import { mapState } from 'vuex'
export default {
computed: {
...mapState(['count'])
},
methods: {
sendUpdateCountAction() {
this.$store.dispatch('updateCount')
}
}
}
</script>
Cependant, comme pour mapState
et mapGetters
, il existe un équivalent pour les actions : mapActions
<template>
<div>
<p>{{ count }}</p>
<button @click="updateCount">Increment</button>
</div>
</template>
<script>
import { mapState, mapActions } from 'vuex'
export default {
computed: {
...mapState(['count'])
},
methods: {
...mapActions(['updateCount'])
}
}
</script>
Vous connaissez maintenant les principaux éléments de Vuex !
Entraînez-vous
Vous trouverez le code source des exercices dans le repo GitHub du cours, dans le dossier cafe-with-a-view
. Pour commencer, consultez la branche P4C4-Begin
.
Instructions
Migrez l'événement d'ajout au panier de
Home.vue
etMenuItem.vue
vers Vuex.Créez une mutation qui met à jour le
state
du shoppingCart.Créez une action qui peut être déclenchée depuis
MenuItem.vue
qui met à jour le panier d'achat dansHome.vue
En résumé
Dans ce chapitre, vous avez découvert :
ce que sont les mutations et les actions ;
comment utiliser les mutations pour mettre à jour le state ;
comment utiliser les actions pour gérer vos mutations ;
comment déclarer et utiliser des actions dans vos composants.
C'est maintenant le moment de passer en revue nos acquis de la partie. Rendez-vous au prochain chapitre !