Open menu

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.