L'archive des sources (répertoire src) pour les démonstrations est téléchargeable [ ici ]
2°/ Principes basiques de Vuex
2.1°/ state et mutations
state: {
count: 0
}
state: () => ({
count : 0
)}
mutations: {
increment(state, amount) {
state.count += amount
}
}
2.2°/ accès et manipulation du store
2.2.1°/ accès à state en lecture
- Exemple :
<template>
<div>
{{ $store.state.count }}
{{ mycount }}
</div>
</template>
<script>
export default {
computed: {
mycount() { return this.$store.state.count }
}
}
</script>
2.2.2°/ accès en modification
Exemple :
<template>
<div>
value: {{ mycount }}
<button @click="$store.commit('increment', 2)"> Inc by 2 </button>
</div>
</template>
<script>
export default {
computed: {
mycount() { return this.$store.state.count }
}
}
</script>
Démonstration 1 :
- Dans le répertoire store, copier index.js.1 dans index.js
- Dans le répertoire views, copier ComponentA.vue.1 dans ComponentA.vue.
- lancer npm run serve, puis ouvrir localhost:8080 dans le navigateur.
- Si on clique sur le lien A, on suit une route (de vue-router) qui permet d'afficher ComponentA. La valeur affichée est 0.
- Si on clique sur le bouton "Inc by 2", la valeur est bien incrémentée de 2.
- Cliquer sur le lien B pour suivre une autre route, puis de nouveau sur le lien A. Miracle : la valeur précédente du compteur est conservée, malgré le fait qu'entre temps, ComponentA a été détruit.
- Normal, car lors de la nouvelle création de ComponentA va chercher calculer la valeur de mycount à partir du store, qui lui est persistant.
3°/ Principes avancés.
3.1°/ Les getters
Exemple :
- Dans store/index.js
{
state: () => ({ count:0 }),
getters: {
doubleCount(state) { return state.count*2 },
fifthCount : (state, getters) => (state.count+getters.doubleCount*2)
}
}
- Dans un composant :
<template>
<div> {{ count }} {{ doubleCount }} {{ fifthCount }} </div>
</template>
<script>
export default {
computed: {
count() { return this.$store.state.count },
doubleCount() { return this.$store.getters.doubleCount },
fifthCount() { return this.$store.getters.fifthCount },
}
}
</script>
Démonstration 2 :
- Dans le répertoire store, copier index.js.2 dans index.js
- Dans le répertoire views, copier ComponentA.vue.2 dans ComponentA.vue.
- Les codes ainsi copiés correspondent en gros à l'exemple donné ci-dessus.
- lancer npm run serve, puis ouvrir localhost:8080 dans le navigateur.
- Si on clique sur le lien A. Les valeurs affichées sont 0 0 0.
- Quand on clique sur le bouton, on voit que les valeurs changent conformément aux calculs fait dans les getters.
3.2°/ Les actions
Exemple :
- Dans store/index.js :
state: () => ({
count:0
}),
mutations: {
increment(state, amount) {
state.count+= amount
}
},
actions: {
incrementAsync(context, amount) {
setTimeout(() => {
context.commit('increment',amount)
}, 1000)
}
}
- Dans un composant :
<template>
<div >
{{ count }}
<button @click="$store.dispatch('incrementAsync',3)">Inc async by 3</button>
</div>
</template>
Démonstration 3 :
- Dans le répertoire store, copier index.js.3 dans index.js
- Dans le répertoire views, copier ComponentA.vue.3 dans ComponentA.vue.
- Les codes ainsi copiés correspondent en gros à l'exemple donné ci-dessus.
- lancer npm run serve, puis ouvrir localhost:8080 dans le navigateur.
- Si on clique sur le lien A. Les valeurs affichées sont 0 0 0.
- Quand on clique sur le bouton "Inc async by 3", on voit que les valeurs changent conformément aux calculs fait dans les getters, mais seulement au bout de deux secondes.
- Cliquer sur le bouton de nouveau puis rapidement sur le lien B. On voit ComponentB s'afficher, ce qui prouve bien que le moteur JS n'est pas resté bloqué sur setTimeOut().
- Quand on revient sur ComponentA, les valeurs ont bien changé, preuve que le traitement n'a pas été interrompu par le changement de page.
- Cliquer trois fois rapidement sur "Inc async by 3" : au bout de 3 secondes, les incrémentations apparaissent successivement.
3.3°/ Les mappers.
Exemple :
- Dans store/index.js :
state: () => ({
count:0,
tab: []
}),
mutations: {
increment(state, amount) {
state.count+= amount
},
store(state, value) {
state.tab.push(value)
}
},
getters: {
doubleCount(state) { return state.count*2},
fifthCount: (state,getters) => (state.count + getters.doubleCount*2),
getItem: (state) => (id) => (state.tab[id]) //renvoie une fonction qui elle-même renvoie tab[id]
},
actions: {
incrementAsync(context, amount) {
setTimeout(() => {
context.commit('increment',amount)
}, 2000)
}
}
- Dans un composant :
<template>
<div class="about">
<h1>This is ComponentA</h1>
{{ count }} {{ doubleCount }} {{ fifthCount }}
<button @click="increment(2)">Inc by 2</button>
<button @click="incrementAsync(3)">Inc async by 3</button>
<hr />
<button @click="store(count)">Store current value</button>
tab = {{ tab }}, tab value in <input v-model="index"> : {{ getItem(index) }}
<hr />
index: {{ index }}, modified: {{ plusFive }}
</div>
</template>
<script>
import {mapState, mapGetters, mapMutations, mapActions} from 'vuex'
export default {
name: 'ComponentA',
data: () => {
return {
index: 0
}
}
,computed: {
plusFive() { return this.index+5 },
...mapState([ 'count', 'tab']),
...mapGetters(['doubleCount','fifthCount','getItem'])
},
methods: {
...mapMutations(['increment','store']),
...mapActions(['incrementAsync'])
}
}
</script>
Démonstration 4 :
- Dans le répertoire store, copier index.js.4 dans index.js
- Dans le répertoire views, copier ComponentA.vue.4 dans ComponentA.vue.
- Les codes ainsi copiés correspondent à l'exemple donné ci-dessus.
- lancer npm run serve, puis ouvrir localhost:8080 dans le navigateur.
- Cliquer sur les différents boutons pour constater que tout fonctionne comme attendu, malgré l'utilisation des helpers.
3.4°/ Les modules
Par exemple :
- Dans module1.js
export default {
namespaced : true,
state: () => ({
count:0
}),
mutations: {
increment(state, amount) {
state.count+= amount
}
}
}
- Dans module2.js :
export default {
namespaced : true,
state: () => ({
tab: []
}),
mutations: {
store(state, value) {
state.tab.push(value)
}
},
getters: {
getItem: (state) => (id) => (state.tab[id])
}
}
- Dans index.js :
...
import module1 from './module1.js'
import module2 from './module2.js'
export default new Vuex.Store({
modules: {
module1,
module2
}
})
- Dans un composant :
<script>
import {mapState, mapGetters, mapMutations, mapActions} from 'vuex'
export default {
...
computed: {
...mapState('module1',['count']),
...mapState('module2',['tab']),
...mapGetters('module2',['getItem'])
},
methods: {
...mapMutations('module1',['increment']),
...mapMutations('module2',['store'])
}
}
</script>
Démonstration 5:
- Dans le répertoire store, copier index.js.5 dans index.js
- Dans le répertoire views, copier ComponentA.vue.5 dans ComponentA.vue.
- Les codes ainsi copiés correspondent en gros à l'exemple donné ci-dessus.
- lancer npm run serve, puis ouvrir localhost:8080 dans le navigateur.
- C'est le même résultat que la démonstration 4, mais en ayant modularisé le store.