Vue.js で状態管理をかじりつつ遅延したフォーム処理をする

フロント開発がもっと楽しくなる!Vue.js 学習メモ。状態管理を少しかじりながらフォームのコンポーネントを作ります。

状態管理って何?Flux?ストア?ディスパッチ?アーキテクチャ?俊足?コーナーで差をつけろ!

ここへ来ると良くかわからない言葉が沢山出てきてつらいです。今までは何も考えずにとりあえず今動けば良いや精神で作っていたのです。

Vuex の基本となっている Flux という概念もよく分かっていないためいきなり完璧なものを作るのは無理なので徐々に取り入れながら Vue の勉強をしていきたいと思います。

状態管理について

今までいくつかコンポーネントを作ってきましたが、親子関係の場合は propsemit を使い、親子関係じゃない場合はイベントバスという空の Vue インスタンスを使いました。同じデータを参照するコンポーネントが増えたりネストが増えると、一つ上に emit で送信して またその上に emit で送信して…という苦行がもれなく付いてきます。

状態管理で参照先を固定にしておくとこの苦行が楽になるというお話。簡単に言えばどこからでも参照できるデータ state (状態)が入った入れ物(ストア)を1つだけ作って、データが必要な時はそれを参照してね、ただしデータを操作する時はストア専用のルートを通ってね!という感じみたいです。

Vuex について

Vuex でよく見る図です。この類の図を見ると眠くなりますが一個づつ理解していきましょう…。

コンポーネントからディスパッチという命令を送るとアクションに繋がってますね。API 等からデータを受け取ったりするのはこの部分みたいです。アクションの結果をコミットという命令でミューテーションに送ってストアが持っているデータを実際に書き換えるのはミューテーションという事みたいです。うぅん…初めてだととてもややこしい。

Vuex の一番最初の説明にもこう書いてあるのです。

Vuex を導入した場合、冗長で恐ろしいと感じるかもしれません。そう感じることは全く普通です。あなたのアプリがシンプルであれば、Vuex なしで問題ないでしょう。

~ おわり ~

とはいかないんだよなぁ。Vue 同様に Vuex のマニュアルも翻訳されていて知りたいことがしっかり載っていたのでひととおり読むだけでもだいぶ分かってきました。ストア内の構成はこんな感じみたいです。

ステート State

実際の状態(最新のデータ)が入ったもの。ミューテーション以外で直接書き換えてはいけない。

ミューテーション Miutation

ステートを変更させるロジック。非同期処理を含めてはいけない。

コミット Commit

ミューテーションを実行する命令。

アクション Action

非同期処理を行うロジック。API からデータを取得したりなど。
実際ステートを操作する場合はここからミューテーションしなければいけない。
逆に同期処理だけなら直接コミットでもOK。

ディスパッチ Dispatch

アクションを実行する命令。

ゲッター Getter

ステートを取得する際の処理。ストア専用の算出プロパティ的なもの。

これ以外にもいくつかありましたが、まずはこの辺のルールを押さえておけば大丈夫そうです。

遅延するフォームを作ってみる

今日書いていた「データを遅延して反映させるフォーム」というのを Vuex を使って書き直してみました。カテゴリ→子アイテムリストという2階層のデータを持っていて、カテゴリ編集をする時個別に反映しないで決定ボタンを押したタイミングで反映する動きにしたいと思います。

元々は cmp-editor に編集中のIDを渡す時に親子間ではないので $root.$refs.editor... という書き方をしていたんですが、編集中のIDをストアで管理するようにしました。非同期処理はしてないのでアクションは使っていません。

cmp-editor-item をコンポーネントにしないで cmp-editor のスコープ内に収めるともう少しシンプルになるのですが、基本的にこう言う場合ってもっとごちゃごちゃしてきてコンポーネント化したい!となるはずなのでコンポーネント前提で作っています。

フローチャートはこんな感じです(作るのむずかしい)

編集中IDの更新と決定したカテゴリの状態の更新の2つのミューテーションを作りました。cmp-editor 以下は editid が更新されたタイミングで内部データでクローンを作りその内部データを子の cmp-ediitor-item に渡しています。データは全部ストアで持たないといけないわけでもなく、ローカルデータと織り交ぜながら使うといいより感じになりそうですね(๑'ᴗ'๑)

実際にデータベースにデータを保存したい場合は、最後のコミットの前にアクションを追加してバックエンドが成功したらフロントでも再取得か直接操作のコミットをするという感じになると思います。

簡単な連携方法

ステートやゲッターは算出プロパティ、ミューテーションやアクションはメソッドに使用 or 登録して実際に使えるようになるのですが、数が多い場合は mapState や mapMutations というマッピング用オブジェクトを使うとシンプルに書けるようです。

script で簡単に使用する場合は Vuex.mapState()Vuex.mapMutations() という感じで使えます。

var app = new Vue({
  el: '#app',
  store,
  computed: Vuex.mapState([
    'list',
    'editid'
  ]),
  methods: Vuex.mapMutations(['updateItems']),
  components: { 'cmp-cat': cmpCat, 'cmp-editor': cmpEditor },
})

まとめ

今回は本当少しだけですけどゲッターやミューテーションをかじってみました(•ө•)ノ ステートを参照する場合は単純に返す場合もゲッターを通した方が良いんでしょうか?

次はアクションも使っていきたいなーと思います。

Edited on 2017.04.20 Created on 2017.03.20 Vue.js JavaScript Webデザイン