Vuexのstate/getters/mutations/actionsについて調べた
JavaScript関連の基礎学習なう。
今回はVuexのステート・ゲッター・ミューテーション・アクションについて調べた。
ストアインスタンスの生成
Vuexを使用するには、まずストアオブジェクト
を作成し、Vueインスタンスに登録する。
ストアオブジェクト
の状態は、state
プロパティで持つことができる。
登録されたストアオブジェクトは、this.$store
を介してVueインスタンス内のすべてのコンポーネントから参照できる。
// main.js import Vue from 'vue' import Vuex from 'vuex' import App from './components/App.vue'; // Vuexの使用を宣言 Vue.use(Vuex); // ストアインスタンスの生成 const store = new Vuex.Store({ // 状態はstateプロパティで保持する state: { count: 1, } }) new Vue({ // Vueに作成したストアインスタンスを登録する。 store, render: h => h(App), }).$mount('#app')
// App.vue <template> <div> {{ count }} </div> </template> <script> export default { computed: { count () { return this.$store.state.count // 1 } } } </script>
ストアオブジェクトを使っている状態でも、本来のdataプロパティはローカルステートとして利用できる。
// App.vue <template> <div> {{ storeCount }} {{ localCount }} </div> </template> <script> export default { data: function(){ return { count: 11, } }, computed: { storeCount () { return `store count: ${this.$store.state.count}` // store count: 1 }, localCount () { return `local count: ${this.count}` // local count: 11 }, } } </script>
getters
各コンポーネントで共通のcomputedメソッドがあるとき、共通化の手段としてgetters
オプションが提供されている。
gettersに登録された関数の結果はキャッシュされ、その関数が依存しているstateの値が変更されたときにのみ再評価される。
定義したゲッターは、$store.getters
からアクセスできる(プロパティスタイルアクセス
)。
また、ゲッターの戻り値を関数にすることで、ゲッター自身に引数を渡せるようになる(メソッドスタイルアクセス
)。ただし、メソッドスタイルアクセスのゲッターについては結果はキャッシュされず、実行のたびに計算が行われる。
// main.js import Vue from 'vue' import Vuex from 'vuex' import App from './components/App.vue'; Vue.use(Vuex); const store = new Vuex.Store({ state: { count: 1, }, // getterの定義 getters: { // stateオブジェクトには、第一引数からアクセスできる storeCount (state) { return `store count: ${state.count}` }, // 関数を戻り値にすることで、getterに引数を渡せるようになる。 totalCount(state) { return function(localCount){ return `total count: ${state.count + localCount}` }; } } }) new Vue({ store, render: h => h(App), }).$mount('#app')
// App.js <template> <div> {{ storeCount }} {{ localCount }} {{ totalCount }} </div> </template> <script> export default { data: function(){ return { count: 11, } }, computed: { storeCount () { return this.$store.getters.storeCount // store count: 1 }, localCount () { return `local count: ${this.count}` // local count: 11 }, totalCount () { return this.$store.getters.totalCount(this.count) // total count: 1 }, } } </script>
mutations
ストアの状態は、ミューテーションによってのみ変更される。
ミューテーションはタイプ
とハンドラ
を持ち、ハンドラ関数は直接実行することができない。
実行するためには、store.commit
をタイプを指定して呼び出す必要がある。
また、ハンドラ関数は非同期処理を行なってはならない
。
// main.js import Vue from 'vue' import Vuex from 'vuex' import App from './components/App.vue'; Vue.use(Vuex); const store = new Vuex.Store({ state: { count: 1, }, getters: { storeCount (state) { return `store count: ${state.count}` }, totalCount(state) { return function(localCount){ return `total count: ${state.count + localCount}` }; } }, // ミューテーションの定義 mutations:{ // stateオブジェクトには、第一引数からアクセスできる // 第二引数から、commitに渡された値を受け取れる。 increment(state, payload){ state.count += payload.num; } } }) new Vue({ store, render: h => h(App), }).$mount('#app')
// App.vue <template> <div> {{ storeCount }} {{ localCount }} {{ totalCount }} <input type="button" @click="storeCountIncrement" value="increment"> </div> </template> <script> export default { data: function(){ return { count: 11, } }, computed: { storeCount () { return this.$store.getters.storeCount // store count: 1 }, localCount () { return `local count: ${this.count}` // local count: 11 }, totalCount () { return this.$store.getters.totalCount(this.count) // total count: 1 }, }, methods: { storeCountIncrement(){ // 第一引数にタイプを指定する。引数が必要な場合は第二引数に指定する。 this.$store.commit('increment', {num: 1}); // commitには以下のように、オブジェクトを渡すこともできる // this.$store.commit({ // type: 'increment', // num: 1 // }); } } } </script>
actions
アクションもミューテーションと同じくタイプ
とハンドラ
を持ち、ハンドラ関数の実行にはstore.dispatch
をタイプを指定して呼び出す。
ミューテーションとの違いは以下。
- 自身は状態を変更しない。変更するにはミューテーションをコミットする。
- 任意の非同期処理を含むことができる。
// main.js import Vue from 'vue' import Vuex from 'vuex' import App from './components/App.vue'; Vue.use(Vuex); const store = new Vuex.Store({ state: { count: 1, }, getters: { storeCount (state) { return `store count: ${state.count}` }, totalCount(state) { return function(localCount){ return `total count: ${state.count + localCount}` }; } }, mutations:{ increment(state, payload){ state.count += payload.num; } }, actions: { // 第一引数にはコンテクストオブジェクト(後述)が渡され、ここからcommitできる。 // 第二引数から、dispatchに渡された値を受け取れる。 increment(context, payload){ context.commit('increment', payload); } } }) new Vue({ store, render: h => h(App), }).$mount('#app')
<template> <div> {{ storeCount }} {{ localCount }} {{ totalCount }} <input type="button" @click="storeCountIncrement" value="increment"> </div> </template> <script> export default { data: function(){ return { count: 11, } }, computed: { storeCount () { return this.$store.getters.storeCount // store count: 1 }, localCount () { return `local count: ${this.count}` // local count: 11 }, totalCount () { return this.$store.getters.totalCount(this.count) // total count: 1 }, }, methods: { storeCountIncrement(){ // 第一引数にタイプを指定する。引数が必要な場合は第二引数に指定する。 this.$store.dispatch('increment', {num: 1}); // commitと同じく、オブジェクトを渡すこともできる // this.$store.dispatch({ // type: 'increment', // num: 1 // }); } } } </script>
本文中のコードは以下にまとめてあります。 Vuex調査