この前はVue.jsを使って、なんとなくVueっぽく単一ファイルコンポーネントを使ってフロントエンド開発が出来ることを確認しました。
しかし、何やら最近のフロントエンドでは、状態管理なるものをしていかないと話にならんようです。 というわけで、今回はVuexを使った状態管理の方法を勉強してみたので、そのメモです。
参考にしたのは、前回同様こちらです。
- 作者: 川口和也,喜多啓介,野田陽平,手島拓也,片山真也
- 出版社/メーカー: 技術評論社
- 発売日: 2018/09/22
- メディア: 単行本(ソフトカバー)
- この商品を含むブログを見る
初学者向けでは無いですが、ちゃんと書いてるあるので頑張って読んでみました。
状態管理
Flux
Vuexに入る前に、前提としてFluxについて知っておく必要があるようです。 なにせ、この界隈のデファクトスタンダードなんで。
アプリケーションをちゃんと作っていくと、アプリケーション内部で絶えず更新されていくデータが発生します。 これを状態と呼んでいます。 この状態管理を甘く見ると規模が大きくなったときに、どんどんアプリケーションが複雑化して手に負えなくなります。
フロントエンドにおける状態管理、データフロー設計のパターンとして有名なのがFluxという、Facebookが提唱したモデルだそうです。
Fluxでの状態管理のイメージはこんな感じです。
構成としては、4つのコンポーネントからなっている事がわかります。
- Dispatchers :
- Stores
- Actions
- Views
中身をGoogle翻訳先生に聞くと、こんな感じでした。
Dispachers
Dispatcherはactionを受け取り、それらをdispatcherに登録したstoreに適用します。すべてのstoreはすべてのactionを受け取ります。各アプリケーションに存在するシングルトンディスパッチャは1つだけです。
Stores
storeはアプリケーションのデータを保持するものです。storeは、actionを受け取ることができるようにアプリケーションのdispatcherに登録します。store内のデータは、actionに応答することによってのみ変更される必要があります。ストアにはパブリックセッターは存在せず、ゲッターのみが存在します。storeはどのようなactionに応答するかを決定します。storeのデータが変更されるたびに、 "change"イベントを発行しなければなりません。各アプリケーションに多数のstoreがあるはずです。
Actions
actionはアプリケーションの内部APIを定義します。それらは何かがあなたのアプリケーションと相互作用するかもしれない方法を捉えます。それらは「タイプ」フィールドといくつかのデータを持つ単純なオブジェクトです。
Views
storeからのデータはviewに表示されます。viewはあなたが望むどんなフレームワークも使うことができます(ここでのほとんどの例ではReactを使います)。viewがstoreからのデータを使用するときは、そのstoreからの変更イベントにもサブスクライブする必要があります。その後、storeが変更を発行すると、ビューは新しいデータを取得して再レンダリングできます。コンポーネントがstoreを使用していて、それを購読していない場合は、わずかなバグが見つかるのを待っている可能性があります。ユーザーがアプリケーションのインターフェースの一部と対話すると、通常アクションはviewからディスパッチされます。
Vuex
Vuexとは
「ここまでFluxの説明だったんだからVuexもFluxなんだよな?」って聞こえてきそうですが、それとも若干違います。
VuexもFlux同様、単方向のデータフローになっています。
若干違うのは、Fluxで言うところのDispatcherはVue.jsに内包されてしまっていることです。 上のデータフローを実現するためのVuexにおける状態管理モデルは、公式サイトによればこんな感じらしいです。
データフローの設計のポイントとしては、下記の3つになります。
- 信頼できる唯一の情報源
- 状態の取得・更新のカプセル化
- 単方向のデータフロー
実際に作ってみれば、この辺を意識すると思いますし、細かい話は本にお任せします。
いつ、Vuexを使うべきか
Redux の作者、Dan Abramov の引用によれば、
Flux ライブラリは眼鏡のようなものです: それらが必要になったときに知るのです。
だそうです。 必要になったらでいいみたいですね。
Vue.js自体は確かに他の状態管理ライブラリを使用する事もできますし、状態管理ライブラリを使用しないという方法もあります。 しかし、Vue.jsの思想に則って状態管理を効率よくしようとすると、Vuexを使用することが望ましいと言えます。
Vuexのコンセプト
Vuexのデータフローは上で紹介しましたが、もう少しだけ細かい粒度で書くとこんな感じになるようです。
概念としては、アプリケーションで唯一の信頼できる情報源であるストアがあって、その構成要素としてアクション、ミューテーション、ステート、ゲッターが存在するようになります。 実際にその概念に沿って作ることをvuexでは推奨されるので、結果的に上で示したデータフローパターンに従うことができます。
ストア
ストアはVuexにおける唯一の信頼できる情報源です。 そのため、アプリケーション内で常に1つしか存在しないように実装します。 (Vuexもそれを前提に実装されているようです)
ステート
Vuexにおけるステートはアプリケーション全体の状態を保持するオブジェクトです。 逆に特定のコンポーネントでしか使用しない状態(データ)はステートに保持すべきではないようです。
この辺りは設計指針によるんでしょうね。
ゲッター
ゲッターはステートから別の値を算出するためなどに用いられる関数です。 ステートを組み合わせて別の値を算出する関数なので、様々なところでこの関数を参照して様々な値が算出されます。
ミューテーション
ミューテーションはステートを更新するための関数です。 Vuexではミューテーション以外がステートの値を更新することを規約上禁止しています。
これが守られることで、アプリケーションの状態の複雑化を避けることが可能になります。
アクション
非同期通信や外部APIとの通信を行い、最終的にミューテーションを呼び出す関数をアクションと定義しています。 あくまでミューテーションを呼び出す機能なので、ステートの変更は行いません。
Vuexを使ってみる
必要に迫られているわけではないですが、とりあえず使ってみます。
やっててハマったポイント
やっていてちょっとハマってしまったので先にどこでハマったかを示します。 個人的にハマったところは、「結局のところどのファイルを編集すればいいのか?」という点でした。 今回はそのへんを意識してメモしていきたいと思います。
作るもの
前回作ったページを改良していきます。 具体的に言うと、サンプルで入れていたデータを対象に状態管理してみます。
ざっくり設計
データの管理としてはこんな感じにしたいと思います。
実装一部抜粋
ストアは全体で1つだけなので、store.jsに定義していきます。
合わせて、main.jsでそれを読み込みます。
ただ、外部から呼び出されないといけないので、呼び出し元もちょっとだけいじくります。
大まかにはこんな感じでいけるかと思います。
できたもの
こんな感じになりました。 見た目は前回と変わんないので、割愛します。
https://github.com/nogawanogawa/bootstrap_test
感想
難しいですね。もっといろいろやりたいんですが、エラーでまくってたんでそのへんはまた今度にします。 cytoscape使うといろいろ様になってる図が出るんで、twitter apiとかと連携させたら面白い図が出そうです。
あと、Vueの勉強をすればするほど、Reactの勉強がしたくなりますね。隣の芝は青く見える的な。
まあ、ちゃっちゃと作れるのがVueのいいところですし、しばらくフロントエンドエンジニアに転職する予定もないので、Reactは気が向いたら勉強することにします。