まえがき
以前 Vue.js用のFluxライクなライブラリVuexを試してみる という記事を書きました。2年前の記事で更新もしていなかったので改めて整理して学び直してみようと思います。今回使用するバージョンは 3.0.1
です。
Vuexとは?
VuexはVue.js用の状態管理ライブラリです。Fluxの影響を受けています。ReactだとReduxに当たります。
Fluxの考え方はFacebookのリポジトリにあるflux-conceptsが詳しいです。その中の図をお借りすると以下のような考え方になります。
Action → Dispatcher → Store → View のようにデータが流れていきます。Vuexでもこの考え方と同じようなデータの流れになります。
Vuexでのデータの流れは Actions → Mutations → State → Vue Components となります。それぞれの名前が違うだけでFluxの考え方を素直に取り入れている感じがします。
FluxはコンセプトなのでAPIとの通信は特に指定されていませんが、Vuexはその実装なのでベストプラクティスがあります。図を見ると一目瞭然ですが、ActionsでAPIを叩くように図では指示されています(とはいえFluxの流れをくんでいれば大体Action相当の場所でAPI通信を行うのではないでしょうか)。MutationsではDevtoolsとやりとりを行います。
VuexはVue.jsを使う際Fluxでデータ管理を行いたいとき一番使いやすいライブラリといえるでしょう。Vuexを使用するには、Vue.jsの他のプラグインと同様にVue.jsでインスタンスを作る前に use
メソッドで登録します。
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
簡単に使えるのがうれしいところです。
ストア
Vuexで状態管理を行う場合、まずはじめに作るのはストアです。カウントアップするアプリケーションを例にすると以下のように作成していきます。
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
count: 0
},
getters: {
countWithSuffix(state) {
return `${state.count} 回`
}
},
mutations: {
increment(state) {
state.count++
}
},
actions: {
increment(context) {
context.commit('increment')
}
}
})
const app = new Vue({
el: '#app',
computed: {
showCounter() {
return this.$store.getters.countWithSuffix
}
},
store,
methods: {
increment() {
this.$store.dispatch('increment')
}
}
})
<h1>Counter</h1>
<div id="app">
<div>
{{ showCounter }}
</div>
<button @click="increment">
increment
</button>
</div>
ストア内には state
getters
mutations
actions
のプロパティを持ちます。 state
には状態を、 getters
には state
内の状態を元に算出した値を返す関数を、 mutations
には state
のデータを更新する関数を、 actions
にはミューテーションにデータをコミットする関数を入れます。
それぞれ見ていきます。
state
state
にはデータを格納していきます。多くのFluxライクなライブラリと同様に、Vuexも単一のstateに全ての情報を詰め込んでいきます。
state
の参照は getters
の関数で行っています。
getters: {
countWithSuffix(state) {
return `${state.count} 回`
}
},
getters
に登録した関数の第一引数に state
が渡されるのでそこから参照します。
state
の更新は mutations
の関数で行っています。
mutations: {
increment(state) {
state.count++
}
},
mutations
に登録した関数でも第一引数に state
が渡されるのでそこから値を更新しています。
このように state
は他の関数に第一引数として渡されて参照と更新を行っていきます。
getters
getters
は主に state
のデータを加工して表示したいときに使用します。今回は count
の数値に「回」を後ろに付加するデコレータのような役割で使用していますが、ToDoリストなどを作るときに、DONEかそうでないかでフィルタした結果を渡すときなどにも使えます。
getters
に登録した関数の第二引数に getters
に登録した他のゲッター関数が渡されます。
getters: {
countWithSuffix(state, getters) {
return `${getters.countWithPrefix} 回`
},
countWithPrefix(state) {
return `第 ${state.count}`
}
},
このように他のゲッター関数を組み合わせて使用することも可能です。
mutations
mutations
は state
を更新する関数を登録します。 mutations
内の関数の呼び出しとして特徴的なことはストアの commit
関数を用いて発火させるということです。先に挙げた例では actions
内の関数で commit
を実行していました。
actions: {
increment(context) {
context.commit('increment')
}
}
commit
関数は呼び出す関数の名前(タイプという)を第一引数に入れ、第二引数に該当ミューテーションで使用する値(ペイロードという)を入れることが出来ます。
mutations: {
increment(state, num) {
state.count += num
}
},
actions: {
increment(context) {
context.commit('increment', 1)
}
}
受け取るミューテーション側の関数も第二引数に値が入ります。この値はオブジェクトを送ることも当然可能です。
さらにもう一つの commit
の使用の仕方としてオブジェクトをそのまま渡すスタイルもあります。
mutations: {
increment(state, payload) {
state.count += payload.num
}
},
actions: {
increment(context) {
context.commit({
type: 'increment',
num: 1
})
}
}
type
には実行する関数名を書き、他のプロパティは渡すデータを登録します。これもミューテーションの関数の第二引数に渡されます。
actions
actions
はミューテーションをコミットする関数を登録します。
actions: {
increment(context) {
context.commit({
type: 'increment',
num: 1
})
}
}
引数として渡される context
オブジェクトは、そこを経由して store
や getters
も参照することが可能です。ミューテーションの関数を実行するためには commit
関数を実行します。 commit
関数に渡す引数は mutations
の節で書いたとおりです。
actions
の関数を実行するには dispatch
関数を Vue のインスタンスで実行します。
methods: {
increment() {
this.$store.dispatch('increment')
}
}
Vue のインスタンス側からストアを参照し、ストアの dispactch
関数を実行します。 dispatch
関数も commit
関数と同じように実行する関数の名前を指定して実行します。
methods: {
increment() {
this.$store.dispatch({
type: 'increment',
num: 2
})
}
}
渡されたデータはアクションの関数の第二引数に渡されます。
actions: {
increment(context, payload) {
context.commit({
type: 'increment',
num: payload.num
})
}
}
このようにしてデータを アクション → ミューテーション → ステート と渡していくことが出来ます。
また、actions
内の関数では非同期処理を行うことが可能です。主にアクションの関数内で外部APIの実行し、値を取得しミューテーションに渡してステートを更新していきます。
まとめ
Vuexの基本的な関数と、それぞれの役割についてカウンターアプリを通して学び直してみました。他にもストアオブジェクトを分割するモジュールという便利な機能があったりします。
今回例で作成したカウンターアプリは以下のURLからコードを見ることが出来ます。実行してみたり改造してみたりしてみてください。
VuexはVueと同様に日本語のドキュメントが充実しています。
もしさらに興味を持った場合はこちらをよむと良いと思います。