第4回 – Vuex入門 – パート1
2019.05.27

妻と娘が里帰りして、一人と一匹のわんこで毎日生活している、むつたくです。
ワーワーキャーキャー騒がしかった日々が懐かしいです。
居なくなるとシーン…としてまして、世の一人暮らしをしている方々はよく耐えられるな、
と常々思ってしまいます。
あ、でも!静かでは無いですよ!
わんこのイビキが聞こえてますのでw
さて、今回はVue.jsに話を戻しまして、Vuexについて触れていこうと思います。
Vuexは覚えるのは大変ですが、中〜大規模のプロジェクトでは、真価を発揮すると思いますので
習得していて絶対損は無いです。
小規模では、あまり発揮しませんが、最初から導入しておくことで、改修に追加に…と、
どんどん規模が大きくなってきても、対応出来ますので、必要であれば、導入しておくことを
オススメします。
やること
- Vuexとは?
- 状態管理パターン
- Vuexを使用する (State / Mutations / Actinos)
(1) Vuexとは?
公式の言葉を拝借しますと、
Vuex は Vue.js アプリケーションのための 状態管理パターン + ライブラリです。 これは予測可能な方法によってのみ状態の変異を行うというルールを保証し、アプリケーション内の全てのコンポーネントのための集中型のストアとして機能します。
うーん…、何を言っているのだろう、となりますが、簡単に言いますと、
データの管理を一元化するためのライブラリです。
数えられる程度のコンポーネントで、それを利用したアプリケーションであれば問題ないのですが、
これが数十個になってくると、このコンポーネントでは今はこのデータを扱っていて、あのコンポーネントはあのデータで、あのデータをそのコンポーネントに渡して…とかやってますと、管理が大変ですよね?
親コンポーネントから子、孫、ひ孫コンポーネントに(その逆も然り)データ受け渡しとかのバケツリレー(propsや$emit)も面倒だと思います。
それらを解決してくれるのが、Vuexとなります。
自分がどの階層にいて親コンポーネントはこれで、子コンポーネントはあれで、なんて考えなくて済みます。データを一元管理してくれますので。
StoreのStateと呼ばれるところにデータを集約し、それを介してコンポーネント同士でデータのやり取りをさせます。
どこにいてもVuexライブラリにアクセスしてしまえば、データを取得できますから。便利ですね!
このことから、少数のコンポーネントで構築したアプリは、恩恵をあまり受けることができないかもしれません。
(2) 状態管理パターン
Vuexは、状態管理を単方向データフローで行っており、公式の図解は以下のようになっています。
Actions
API等と非同期通信を行い、データを取得します。
取得後、データをコミットし、Mutationsを呼び出します。
Mutations
Actionsまたは、コンポーネントよりデータがコミットされたら、呼び出されます。
唯一State内のデータを変更することが出来ます。
State
各コンポーネントで使用するデータはここに集約します。
(3) Vuexを使用する
Vue-CLI 3.*系を前提とします。インストール手順は以前のブログで紹介しています。
vue create <ProjectName>で行った後、Manually select features を選択すると、使用できるものが一覧化されてますが、この中にVuexがありますので、選択しましょう。
後から追加する場合は、vue add vuexを実行します。
準備が整いました。
<ProjectName>ディレクトリ直下にsrcディレクトリがあると思いますが、その中にstore.jsがあります。
ない方は、store.jsを作成するなり、storeディレクトリを作成後、index.jsを作成するなりしてください。
store.jsの中身は以下のようになっています。
[cc_javascript]
//store.js
import Vue from ‘vue’
import Vuex from ‘vuex’
Vue.use(Vuex)
export default new Vuex.Store({
state: {},
mutations: {},
actions: {}
})
[/cc_javascript]
5行目の Vue.use(Vuex) は、書き忘れないようにしてください。このアプリケーション内でVuexを使用しますと言う宣言になります。Vuexが使用できない場合は、描き忘れが無いか確認してください。
ここから簡単な使用方法をカウンターアプリを作成しつつ説明します。
Stateについて
Storeのデータ群をここ(State)で保持
Mutationsでのみ変更される
store.jsを以下のように変更します。
[cc_javascript]
import Vue from ‘vue’
import Vuex from ‘vuex’
Vue.use(Vuex)
export default new Vuex.Store({
state: {
counter: 0 // ★これを追加
},
mutations: {},
actions: {}
})
[/cc_javascript]
componentsディレクトリにcounter.vueを作成し、以下のようにします。
[cc_javascript]
//counter.vue
[/cc_javascript]
$store.state.counter でStore内のStateに登録した変数[counter]にアクセスしています。
次にviewsディレクトリにHome.vueを作成して、以下のようにします。
[cc_javascript]
//Home.vue
[/cc_javascript]
これでcounter.vueが表示されたと思います。この状態だと、「0」が表示されています。
試しに、store.jsのcounterの数値を変更してみてください。
初期値が変更した値になっているはずです。
もう一つコンポーネントを作成してみましょう。reset.vueとします。
[cc_javascript]
//reset.vue
値のリセット
{{ $store.state.counter }}
[/cc_javascript]
ついでにcounter.vueからreset.vueが表示できるように、counter.vueを修正します。
[cc_javascript]
//counter.vue
[/cc_javascript]
これでどちらのページからもcounter.vueが閲覧できるようになりました。実際にlocalhostへアクセスしてみてください。
propsや$emitを使わずに値をそれぞれのコンポーネントで表示できたかと思います!
Mutationsについて
Storeを変更する
Storeのデータをコミットすることで呼び出される
同期処理を行う
実際にStoreをコミットしてMutationsを呼び出してみましょう。
store.jsを以下のように変更します。
[cc_javascript]
//store.js
import Vue from ‘vue’
import Vuex from ‘vuex’
Vue.use(Vuex)
export default new Vuex.Store({
state: {
counter: 0
},
mutations: {
increment (state) { // ★increment{…}追加
// インクリメント用関数
state.counter++
},
reset (state) { // ★reset{…}追加
// カウンターリセット用関数
state.counter = 0;
}
},
actions: {}
})
[/cc_javascript]
これでstoreのcounterの状態を管理する関数が作成できました。関数名の通り、[increment]ではカウントアップを、[reset]ではカウンタを0に戻します。
また、各関数(ハンドラ)は第一引数にVuexの状態を取得します。なので、[increment]も[reset]も第一引数に[state]を定義しています。
引数名は当たり前ですが、何でも構いません。ここではあえてstoreと命名しているだけです。
ちなみに第二引数もあります。通称ペイロードと呼ばれていますが、任意の値を渡したいときに使用します。基本的にオブジェクトで渡します。
※使い方はMutationsの最後の方で。
[cc_javascript]
//store.js
// …省略…
mutations: {
increment (state, payload) {
// インクリメント用関数
state.counter += payload.incrementval
},
reset (state, payload) {
// カウンターリセット用関数
state.counter = payload.resetval;
}
},
actions: {}
})
[/cc_javascript]
次に、mutationsに登録した関数をそれぞれのコンポーネントから呼び出せるようにします。
[cc_javascript]
//counter.vue
[/cc_javascript]
[cc_javascript]
//reset.vue
値のリセット
{{ $store.state.counter }}
[/cc_javascript]
ここまで出来ましたら、再度localhostにアクセスしてみましょう。各コンポーネントにボタンがそれぞれ追加されてます。
試しにcounter.vue側のボタン[カウントアップ]をクリックします。すると、counter.vueと、reset.vueのcounter変数値がインクリメントされてます。
ついでにreset.vue側のボタン[リセット]ボタンもクリックしてみます。どちらのコンポーネントのcounter変数値が初期値に戻ってると思います。
無事、propsや$emitに頼らず、コンポーネント間での値参照に成功しました。
大事なのは、storeで定義したデータを更新させるのはstore内でしか行えず、storeの関数をコールするには、commitします。その際にコールするmutationsの関数名を定義してあげます。そうすることで、mutationsによる値更新を行うことができるようになります。
下記のコードのように、直接store値を変更したり、mutations関数をコールすると、エラーになるので、注意してください。
[cc_javascript]
//counter.vue
//…省略…
[/cc_javascript]
また、mutationsの関数に任意の値を渡したい場合、commitの第二引数を以下のように設定します。
[cc_javascript]
//counter.vue
//…省略…
[/cc_javascript]
こうすることによって、任意の数値分インクリメント(ここでは2ずつ)されるようになりました。
さらに任意の値を渡したい場合は、オブジェクトの中にどんどん追記してあげれば、コールした関数先でも参照することが出来ます。
Actions
commitして、mutationsをコールする
非同期処理を行う
Promiseをリターンする
stateは変更しない
dispatchで呼び出される
mutationsと似ていますが、Actionsはdispatchでコールされるのと、非同期処理を行い、それをPromiseでリターンするという役割を担っています。
では、実際にコードを書いてみましょう。…これ非同期にする必要なくね?とかは受け付けません!
まずは、actionsをdispatchするコンポーネントを作成します。countup.vueとしましょう。
[cc_javascript]
//countup.vue
[/cc_javascript]
ついでにcountup.vueをcounter.vueに組み込みましょう。それから、store.jsのacrionsの箇所も変更しちゃいます。
[cc_javascript]
//counter.vue
[/cc_javascript]
[cc_javascript]
//store.js
//…省略…
actions: {
act_countup({ state }, payload) {
return new Promise((resolve, reject) => {
setTimeout(() => {
state.counter++;
resolve();
}, payload.timer);
})
}
}
})
[/cc_javascript]
ここまで出来ましたら、localhostを再起動します。[重たい処理]ボタンが追加されてます。
クリックすると、dispatchによりactionsに定義した関数[act_countup]がコールされ、2秒後、ログに「countup complete」が出力されてると思います。
非同期処理なので、その間もカウントアップ、値リセットは動きます(使い方が違いますが…)
actionsもmutationsと同様に、第一引数及び、第二引数しかありません。第二引数はmutationsと同じになりますが、第一引数が異なります。
contextと呼ばれますが、オブジェクトになっており、以下6種類あります。
| state | `store.state` と同じか、モジュール内にあればローカルステート |
| getters | `store.getters` と同じか、モジュール内にあればローカルゲッター |
| rootState | `store.state` と同じ。ただしモジュール内に限る |
| rootGetters | `store.getters` と同じ。ただしモジュール内に限る |
| commit | `store.commit` と同じ。mutationsをコールする時に使用。 |
| dispatch | `store.dispatch` と同じ。actionsをコールする時に使用。 |
ローカル〇〇とか出てきますが、同じjsファイルで定義している場合、そこを参照することになります。今回も、これに該当します。同じjsファイルにstateもmutationsもactionsもありますので。
actions側ではこんな感じになります。
[cc_javascript]
act_countup({state, getters, rootState, rootGetters, commit, dispatch}, payload) { … }
[/cc_javascript]
さて、このように非同期処理をactionsでは書けますが、別にmutationsで書くこともできると思います。ただ、actionsで書いた方が融通が利きます。
なぜなら、コードでは書いてませんが、別のactionsへdispatchが出来たり、mutationsのcommitもできるので、処理を柔軟に組み合わせることが出来ます。
ちなみに、async/awaitシンタックスを書くことも出来るので同期的な処理も行えます。
まとめ
Vuexは、Vue.jsのライブラリの一つで状態管理をしてくれる。つまり、データをStoreで一元管理してくれる。
状態管理には3種類あり、state / mutations / actions である。
stateは、Store内のデータを保持してくれる。ここでは、データの変更は出来ない。
mutationsは、stateで保持しているデータの変更を行ってくれる。変更するときはcommitでコールする。
actionsは、stateで保持しているデータの変更を行ってくれる。変更するときはdispatchでコールする。
mutationsと似ているが、最大の違いは、非同期処理を行い、Promiseをリターンすることである。
詳しくは公式ドキュメント(日本語版)がありますので、そちらを参照してください。
おわりに
今回は、Vuexのこと、StoreのState、Mutations、Actionsについて簡単ですが、紹介しました。
少しでもVuexについて理解が深まれば、幸いです。
次回は、Vuexのgetterや、モジュールについて紹介していきます。
それでは、またの機会に!
↓↓↓ぜひチェックしてください
~提供中のヒューマンセンシング技術~
◆なりすまし判定技術
eKYC・顔認証のなりすまし対策を!
https://bio-check.pas-ta.io
◆まばたき検出技術
PCやスマホアプリに組み込めて高精度にまばたきを検出
https://blink.pas-ta.io
◆視距離推定技術
単一RGBカメラで、目からカメラまでの距離を推定
https://vd.pas-ta.io
◆虹彩認証技術
目の虹彩を利用した生体認証技術
https://iris.pas-ta.io
◆視線検出技術
アイトラッキングや次世代UIに
https://eyetrack.pas-ta.io
◆目検出技術
あらゆる目周りデータを高精度に取得
https://pupil.pas-ta.io
