Vue CLI3 で作成した SPA(Single Page Application)プロジェクト上で、段階的に Vue.js を学んで行きましょう。
今回は Vuex 編です。
前提事項
Bootstrap 編 が完了していること。
ページの追加
- Counter.vue を作成
- router.js を修正
- App.vue にナビゲーションを追加
やり方を忘れてしまった人は「Vue Router 編」を振り返ってください。
<template>
<div class="counter">
<h1>Counter</h1>
<p>{{ count }}</p>
<div>
<button
class="btn btn-sm btn-primary"
@click="increment"
>+</button>
<button
class="ml-1 btn btn-sm btn-secondary"
@click="decrement"
>-</button>
</div>
</div>
</template>
<script>
export default {
data() {
return {
count: 0
};
},
methods: {
increment() {
this.count++;
},
decrement() {
this.count--;
}
}
};
</script>
Counter ページを表示して動作を確認してみてください。+
ボタンを押すとカウントアップされて、-
ボタンを押すとカウントダウンします。
Vuex
Vuex はコンポーネントを横断した状態の格納やそれらを操作する為のメソッドを格納する場所です。先程作成したカウンタページを Vuex を使って書き換えてみます。
ステートとミューテーション
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
// 状態
state: {
count: 0,
},
// ストアの状態を変更するメソッド(同期処理のみ)
mutations: {
increment(state) {
state.count++
},
decrement(state) {
state.count--
},
},
// ストアの状態を変更するメソッド(非同期処理もOK)
actions: {},
})
ステートに count
変数を設け、ミューテーションに increment
と decrement
を設けました。ステートはミューテーションを通して変更します。ただし、同期処理に限ります。
<script>
export default {
computed: {
count() {
// vuex 内の count ステートを参照
return this.$store.state.count
}
},
methods: {
increment() {
// vuex 内の increment ミューテーションを実行
this.$store.commit('increment')
},
decrement() {
// vuex 内の decrement ミューテーションを実行
this.$store.commit('decrement')
}
}
};
</script>
vue コンポーネントでは $store
属性で vuex を参照することができます。ミューテーションを実行するには $store
の commit
メソッドを使用します。
ゲッター
vuex にゲッターを追加してみます。count の内容を2倍して返す double
を設けます。
export default new Vuex.Store({
// ...
// ゲッター
getters: {
double(state) {
return state.count * 2
},
},
// ...
})
<template>
<!-- ... -->
<p>count: {{ count }}</p>
<p>double: {{ double }}</p>
<!-- ... -->
</template>
<script>
export default {
computed: {
count() {
// vuex 内の count ステートを参照
return this.$store.state.count;
},
double() {
// vuex 内の double ゲッターを参照
return this.$store.getters.double;
}
},
// ...
};
</script>
画面の double
欄には count
を2倍した値が表示されるはずです。
アクション
アクションはミューテーションと似ていますが、下記の点で異なります
- アクションは、状態を変更するのではなく、ミューテーションをコミットします
- アクションは任意の非同期処理を含むことができます
vuex にアクションを追加してみます
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
// ...
// ストアの状態を変更するメソッド(非同期処理も可、ミューテーションをコミットする)
actions: {
increment(context) {
context.commit('increment')
},
// 引数に ES2015 の引数分割束縛を使った例(context を省略できる)
decrement({ commit }) {
commit('decrement')
},
},
})
アクションのメソッドは context
オブジェクトを引数に受け取ります。context.commit
を実行することでミューテーションをコミットできます。
<script>
export default {
// ...
methods: {
increment() {
// vuex 内の increment ミューテーションを実行
// this.$store.commit("increment");
// vuex 内の increment アクションを実行
this.$store.dispatch("increment");
},
decrement() {
// vuex 内の decrement ミューテーションを実行
// this.$store.commit("decrement");
// vuex 内の decrement アクションを実行
this.$store.dispatch("decrement");
}
}
};
</script>
アクションを実行するには $store
の dispatch
メソッドを使用します。
ヘルパー
vue ファイルの中で、毎回 this.$state.xxx
と書くの面倒ですよね。そのために、ヘルパーが用意されています。
<script>
import { mapState } from "vuex"; // ステートのヘルパーをインポート
import { mapGetters } from "vuex"; // ゲッターのヘルパーをインポート
import { mapActions } from "vuex"; // アクションのヘルパーをインポート
export default {
computed: {
...mapState([
"count" // this.count を this.$store.state.count にマップ
]),
...mapGetters([
"double" // this.double を this.$store.state.getters.double にマップ
])
/* DEL mapState, mapGetters で置き換え
count() {
// vuex 内の count ステートを参照
return this.$store.state.count;
},
double() {
// vuex 内の double ゲッターを参照
return this.$store.getters.double;
}
*/
},
methods: {
...mapActions([
"increment", // this.increment() を this.$sotre.dispatch("increment") にマップ
"decrement" // this.decrement() を this.$store.dispatch("decrement") にマップ
])
/* DEL mapActions で置き換え
increment() {
// vuex 内の increment ミューテーションを実行
// this.$store.commit("increment");
// vuex 内の increment アクションを実行
this.$store.dispatch("increment");
},
decrement() {
// vuex 内の decrement ミューテーションを実行
// this.$store.commit("decrement");
// vuex 内の decrement アクションを実行
this.$store.dispatch("decrement");
}
*/
}
};
</script>
ミューテーションやアクションへの引数の渡し方
この記事では例がシンプル過ぎた為、ミューテーションやアクションへの引数の渡し方を取り上げていません。詳細は公式サイトを参照してください。
動作確認
カウントアップ、カウントダウンが正しく動作しているか確認してください。devtools で vuex の内容を確認してみてください。