目次
15.Vue.jsのvuexでカウンター
vuexをなんとかして理解するために簡単なアプリを写経しています。前回の14.vue.jsのvuexで入力フォームでは、文字を入力すると、そのまま別のコンポーネントで表示するアプリを、vuexを用いて作成しました。
今回は、『カウンターアプリ』を作成しながら、vuexの理解を深めたいと思います。
初めてのVuex目次
すること
- vuexを用いてカウンターアプリを作成する
- 数字が表示されている(App.vueに表示させる)
- 『+1』を押すと、数字が1増える(components/counter.vueで『+1』ボタンを表示する)
- 『-1』を押すと、数字が1減る(components/counter.vueで『-1』ボタンを表示する)
今回は、https://qiita.com/ferretdayo/items/edcd2b6682148e477104を写経させていてだきました。
ソースコード
https://github.com/adash333/Vue_Vuex_Counter
https://codesandbox.io/s/l556xq6327
開発環境
Chrome Codesandbox Vue 2.5.2 Vuetify 1.4.2 Vuex 3.1.0
CodeSandboxで新規Vue.jsアプリを作成
最初に、CodeSandbox上で、新規Vue.jsアプリを作成し、CSSフレームワークVuetifyが利用できるように設定します。
- https://codesandbox.io/へ行き、画面右上の、『Create Sandbox』をクリック
- Vue をクリック
- Add Dependencyから、Vuetifyをインストール
- index.htmlの編集
- src/main.jsの編集
index.htmlと、src/main.jsは、以下をコピペします。
以上で、Vue.jsで、Vuetifyを利用する準備ができました。
Vuetifyのテンプレートを適用
Vue.jsにVuexをインストール
Vuexを利用するための準備を行います。
- Add Dependencyから、Vuexをインストール
- Add Dependencyから、babel-polyfillをインストール
- src/main.jsの編集
- src/store.jsの新規作成
src/main.jsは、以下の2行を追加します。(追加する位置には注意する必要があります。)
import store from './store' store,
この時点では、store.jsを作成していないので、エラーが出ます。
- src/store.jsのテンプレートの作成
src/store.jsを新規作成し、以下をコピペします。
import Vue from "vue"; import Vuex from "vuex"; Vue.use(Vuex); const store = new Vuex.Store({ state: {}, getters: {}, mutations: {}, actions: {} }); export default store;
これでも、まだエラーが出ています。。。
右側の画面の更新画面を押すと、以下のように、vuexが動く準備ができたようです。
Counterコンポーネントを作成し,カウンター機能の追加
まずは、vuexを用いない方法で、カウンター機能を作成します。
- カウンターの表示、カウンターの『+1』、『-1』のボタンをcomponents/counter.vueに設置
でいってみたいと思います。
- src/components/Counter.vueの新規作成
<template> <v-flex xs12 sm6 offset-sm3> <v-card> <v-img src="https://cdn.vuetifyjs.com/images/cards/desert.jpg" aspect-ratio="2.75" ></v-img> <v-card-title primary-title> <div> <h3 class="headline mb-0">{{ count }}</h3> </div> </v-card-title> <v-card-actions> <v-btn v-on:click="decrement">-1</v-btn> <v-btn v-on:click="increment">+1</v-btn> </v-card-actions> </v-card> </v-flex> </template> <script> export default { name: "Counter", data() { return { count: 0 }; }, methods: { increment() { this.count++; }, decrement() { this.count--; } } }; </script>
- HelloWorldコンポーネントでCounterコンポーネントを表示
App.vueとcomponents/Counter.vueを少しだけ変更して、以下のようになった。
+1をクリックと数字が1増えて、-1をクリックすると、数字が1減る。
次は、上記のカウンターの増減を、Vuexを用いる方法に書き換えていきます。
Vuexの説明
Vuexは図のようなデータの流れを持つ,状態管理のパターンです.
- ComponentはdispatchすることでActionsを実行する
- ActionsはCommitすることでMutationsを利用する
- MutationsはStateを変更する
Vuexの図:https://vuex.vuejs.org/ja/より引用
これだけでは何のことかさっぱりわかりません。。。
しかし、アプリが複雑になるほど、Vuexは必要になることは間違いないらしいので、やるしかありません!
(Vuexを用いないでデータをやり取りするためには、親コンポーネントと子コンポーネントの間でpropsと$emitのデータのバケツリレーが必要いなるためらしいです。)
今度こそ、上記のカウンターアプリをVuexを用いたアプリにします。
カウンター機能にVuexを利用
以下の3つを行う必要があるそうです。(参考:カウンター機能にVuexを利用)
- src/store.jsファイルを新規作成し,state, actions, mutations, gettersを定義 (済み)
- src/main.jsにstoreファイルに書かれたstoreを登録 (済み)
- CounterコンポーネントからVuexを利用
src/store.jsファイルの編集
stateとかactionsとか言葉がたくさん出てきますが、以下を、100回くらい声に出して読んで、写経していくしかなさそうです。。。(参考:カウンター機能にVuexを利用)
- stateには状態を持ちたい情報を定義する
- actionsでアクションを定義,commitすることでmutationsが実行される
- gettersはコンポーネントがデータを取得する際に利用される
- mutationsはstateの状態を変更する際に利用される
- gettersとmutationsのメソッドの引数には定義したstateが代入される
- actionsのメソッドの引数のcontextにはdispatch,commit,getters,stateを持つオブジェクトが代入される
- 引数に{ commit }とすると,commitだけ利用できる.
actionsのメソッドの引数は、commitの場合は、上記の通り、2通りの書き方があるそうです。
(contextの中にcommitがあるだけですが。)
const actions = { increment(context) { context.commit("increment"); }, decrement({ commit }) { commit("decrement"); } };
src/main.jsにstoreを登録
上の方で、登録済みです。
import store from "./store"; // new Vue の中に、 store,
CounterコンポーネントからVuexの利用
src/main.jsで追記したstoreを利用するにはthis.$storeから利用するとのことです。(参考:CounterコンポーネントからVuexの利用)
上記サイトを写経しているだけで、詳しいことはよくわからないのですが、とにかく、$this.store.stateでstateをゲットしてくるらしいです。。。
- state :stateにアクセスする際に利用
- dispatch :actionsで定義したメソッド名を引数に渡すことで,actionを実行できる
- getters :ここからgettersで定義したメソッドを利用できる
- commit :mutationsに定義したメソッド名を引数に渡すことで,mutationを実行できる
今回のカウンターアプリでは、store.jsからのデータの取得にはcomputedで,storeのgettersで定義したcountの値を返すgetCountメソッドを利用します。
computed: { count () { return this.$store.getters.getCount } },
src/components/Counter.vue
(変更前)
(変更後)
カウンターの初期値や、+1、-1の状態管理をvuexに移動しても、ちゃんと、カウンターが動くことが確認できました。
ここまでのソースコード(CodeSandeboxバージョン)
mapGetters, mapActionsを用いてVuexのコードを少し発展させる
mapState, mapGetters, mapMutations, mapActionsといったヘルパーと、スプレッド演算子『…』を用いると、記載するコード量を減らすことができます。
(いきなりこれを見ると、『わけわからん状態』ですが、上記の経過をたどった後であれば、何となく分かった気になれる気がします。)
import { mapState, mapGetters, mapMutations, mapActions } from 'vuex'
stateとgetterは算出プロパティcomputedに登録します。
mutationとactionはメソッドmethodsに登録します。
computed: { // ローカルの算出プロパティ myProperty() { ... }, ...mapGetters([ // this.messageをstore.getters.messageにマッピング 'message' ]), // メソッド名を変更したい場合はオブジェクトで定義 ...mapGetters({ // this.messageAliasをstore.getters.messageにマッピング messageAlias: 'message' }) }
カッコが、[]なのか、{}なのか、紛らわしいです。[]は配列、{}はオブジェクトなのだと思います。
組み合わせる必要がなければ、以下のように、オプションに直接、登録することもできるとのことです。
(しかし、これは汎用的ではないと思われます。)
computed: mapGetters(['message']), methods: mapActions(['add', 'update', 'remove'])
上記のカウンターアプリを、mapGetters, mapActionsを用いて書き換えると、以下のようになります。
import { mapGetters, mapActions } from 'vuex' export default { name: 'Counter', computed: { count () { return this.$store.getters.getCount } }, methods: { ...mapActions([ 'increment', 'decrement' ]) } }
今回のアプリ作成はここまでとなります。
Vuexでカウンターアプリのリンク
https://qiita.com/ferretdayo/items/edcd2b6682148e477104
@ferretdayo
2017年12月23日に更新
IDOM Engineer Advent Calendar 201723日目
カウンターを作りながら,VueとVuexの基本をやる
→最初はこちらを写経でしょうか?
- Vuexを利用しないでカウンターアプリを作成
- Vuexを利用したカウンターアプリに変更
- Vuexのコードを発展させる(mapActions,mapState,mapGetters,mapMutationsの利用)
https://qiita.com/nasum/items/d17c0a628e6c32616b85
@nasum
2017年12月17日に更新
Vue.js #4 Advent Calendar 201717日目
改めて学び直すVuex
→カウンターアプリを作成します。
https://qiita.com/d-dai/items/7df318b9369be3d58a58
@d-dai
2018年11月25日に更新
Vuexの簡単なサンプルを作ってみた
→カウンターアプリを作成します。
ソースコード
リンク