業務でVuexをいじっているが、理解ができていないままいじっていたので一度概要をざっとまとめてみようと思った。
Vuexとは何か?
まずは公式を参照。
Vuex は Vue.js アプリケーションのための 状態管理パターン + ライブラリです。 これは予測可能な方法によってのみ状態の変異を行うというルールを保証し、アプリケーション内の全てのコンポーネントのための集中型のストアとして機能します。 https://vuex.vuejs.org/ja/
なんとなーーーーーーく上澄みくらいはわかる。
ただこの説明だけでは、
「状態管理パターン?」
「予測可能な方法によってのみ状態の変異を行うというルール?」
「集中型のストア?」
というような深い部分についてわからなかったので、ドキュメントやVuexについてまとめられている記事を参考にしてめちゃくちゃ大雑把にまとめてみた。
状態管理パターン
公式に状態管理パターンの説明があったので引いてみる。
コンポーネントから共有している状態を抽出し、それをグローバルシングルトンで管理するのはどうでしょうか? これにより、コンポーネントツリーは大きな "ビュー" となり、どのコンポーネントもツリー内のどこにあっても状態にアクセスしたり、アクションをトリガーできます!
さらに、状態管理に関わる概念を定義、分離し、特定のルールを敷くことで、コードの構造と保守性を向上させることができます。
ほうほう。
つまり、
- コンポーネント間で共有している状態はグローバルシングルトンで管理される
- 管理されているデータはどこからでもアクセスできる
- 管理は特定のルールのもとに行われる
ということらしい。
「別に props
や $emit
でデータのやりとりできるからええんちゃう?」と思ったが、それではどうやらだめらしい。
なぜ状態管理をこのように管理しないといけないか?
このことについても公式に説明があった。
(状態、ビュー、アクションという"単方向データフロー"のコンセプトの極めてシンプルな責務の)単純さは、共通の状態を共有する複数のコンポーネントを持ったときに、すぐに破綻します: - 複数のビューが同じ状態に依存することがあります。 - 異なるビューからのアクションで、同じ状態を変更する必要があります。 一つ目は、プロパティ (props) として深く入れ子になったコンポーネントに渡すのは面倒で、兄弟コンポーネントでは単純に機能しません。二つ目は、親子のインスタンスを直接参照したり、イベントを介して複数の状態のコピーを変更、同期することを試みるソリューションに頼っていることがよくあります。これらのパターンは、いずれも脆く、すぐにメンテナンスが困難なコードに繋がります。
※括弧は自分が追記
これをめちゃくちゃ簡単にまとめると、
「Action→State→Viewというフローが、複数のコンポーネントでデータを共有する場合に崩壊してしまい、またコードの保守性の低下につながる」
ということ。
このような問題をVuexの機能を使うと解決できる。
その機能が冒頭で触れた下記の3つ。
- コンポーネント間で共有している状態はグローバルシングルトンで管理される
- 管理されているデータはどこからでもアクセスできる
- 管理は特定のルールのもとに行われる
この部分については下記の記事がわかりやすかった。
では、これらの機能についてまとめていく。
ただ、「管理されているデータはどこからでもアクセスできる」はそのままのことなので割愛。
コンポーネント間で共有している状態はグローバルシングルトンで管理される
これは「シングルトン」がわかればいいかと。
シングルトンとは、デザインパターンの1つで、あるクラスのインスタンスが全体で1つしか作成されないこと、つまり1つクラスに対して1つのインスタンスしか作らないということ。
VuexのStoreは全体で1つしか作成されない。
管理は特定のルールのもとに行われる
ここで言う特定のルールとは、「基本的にデータはComponents→Actions→Mutations→State→Getter→Componentsという流れをとる」ということ。
props
と $emit
を使った場合のバケツリレー方式ではなく、5つの要素を経由する一方通行でデータが流れていく。
それぞれの役割について見ていく。
Actions
Actionsの役割は
- Mutationsをコミットする
こと。
つまり、Mutationsを呼び出してデータの更新をさせるのがActionsの役割。
また、Mutations以外の処理も呼び出せ、非同期処理も行える。
Stateの更新以外の処理はActionsで行う感じ。
Mutations
Mutationsの役割は
- Stateを更新する
こと。
ただし、更新は同期的に行わなければならない。
非同期で同時に処理を走らせると単純なデータフローが破綻してしまうため。
State
Stateの役割は
こと。
ひとまずはデータの入れ物みたいな理解でいいかと。
Getter
Getterの役割は
- Stateの内容を加工してComponentsに渡す
こと。
GetterをComponentsmに依存させてしまうとStateの管理が大変になるので注意。
computedにも同じような機能があるが、それとの違いはてりーさんの記事が参考になった。
(computedとの)違いとして
- computedは各コンポーネント単位で実装
- Vuex GetterはState毎で実装
という点なので、複数のコンポーネントでStateに同じ処理を施す必要があるなら、Getterで定義。そうでなければ出来るだけStore管理は軽くしたいので、computedで定義が良さそう。
※括弧は自分が追記
おわりに
まとめる前と比べて少し理解が進んだかなーーーと思う。
あとは実際にコードを見ながら知識を加えていくしかないなぁとしか。
参照ドキュメント
- Vuex公式ドキュメント「Vuexとは何か?」
- https://vuex.vuejs.org/ja/
- 業務で使っているのがVue2とVuex3だったのでドキュメントのバージョンも合わせている
- https://vuex.vuejs.org/ja/
- @tsuji_za「Vue.jsの状態管理パターンVuex、Fluxアーキテクチャについてまとめてみた。」
- TC「Vuexの使い方や責務について」
- クモのようにコツコツと「【Vue.js】Vuexの「状態管理」はいったい何の状態を管理しているのか調べた」
- chmod「【初心者向け】シングルトンパターンをわかりやすく解説」
- てりー「Vuexの基本事項を今更ながらまとめてみる」