====== 15.Vue.jsのvuexでカウンター ======
vuexをなんとかして理解するために簡単なアプリを写経しています。前回の[[14.vue.jsのvuexで入力フォーム:index.html|14.vue.jsのvuexで入力フォーム]]では、文字を入力すると、そのまま別のコンポーネントで表示するアプリを、vuexを用いて作成しました。
今回は、『カウンターアプリ』を作成しながら、vuexの理解を深めたいと思います。
===== 初めてのVuex目次 =====
[[14.vue.jsのvuexで入力フォーム:index.html|14.vue.jsのvuexで入力フォーム]]
[[15.vue.jsのvuexでカウンター:index.html|15.Vue.jsのvuexでカウンター]]
[[16.vue.jsのvuexでパスワード制限:index.html|16.vue.jsのvuexでパスワード制限]]
[[17.nuxt.jsのvuexでパスワード制限:index.html|17.Nuxt.jsの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
Demo
https://l556xq6327.codesandbox.io/
{{:15.vue.jsのvuexでカウンター:pasted:20190126-204253.png}}
===== 開発環境 =====
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の編集
{{:14.vue.jsのvuexで入力フォーム:pasted:20190121-123704.png}}
{{:14.vue.jsのvuexで入力フォーム:pasted:20190121-123723.png}}
{{:14.vue.jsのvuexで入力フォーム:pasted:20190121-123749.png}}
{{:14.vue.jsのvuexで入力フォーム:pasted:20190121-123804.png}}
{{:14.vue.jsのvuexで入力フォーム:pasted:20190121-123835.png}}
index.htmlと、src/main.jsは、以下をコピペします。
{{:14.vue.jsのvuexで入力フォーム:pasted:20190121-124228.png}}
{{:14.vue.jsのvuexで入力フォーム:pasted:20190121-124252.png}}
以上で、Vue.jsで、Vuetifyを利用する準備ができました。
===== Vuetifyのテンプレートを適用 =====
src/App.vueに、以下のコードをコピペします。
{{:14.vue.jsのvuexで入力フォーム:pasted:20190121-124906.png}}
これで、App.vueの土台が出来上がりました。
===== Vue.jsにVuexをインストール =====
Vuexを利用するための準備を行います。
-Add Dependencyから、Vuexをインストール
-Add Dependencyから、babel-polyfillをインストール
-src/main.jsの編集
-src/store.jsの新規作成
{{:14.vue.jsのvuexで入力フォーム:pasted:20190121-141702.png}}
{{:14.vue.jsのvuexで入力フォーム:pasted:20190121-141741.png}}
{{:14.vue.jsのvuexで入力フォーム:pasted:20190121-141941.png}}
src/main.jsは、以下の2行を追加します。(追加する位置には注意する必要があります。)
import store from './store'
store,
(変更前)
{{:14.vue.jsのvuexで入力フォーム:pasted:20190121-142758.png}}
(変更後)
{{:14.vue.jsのvuexで入力フォーム:pasted:20190121-142928.png}}
この時点では、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;
これでも、まだエラーが出ています。。。
{{:14.vue.jsのvuexで入力フォーム:pasted:20190121-143709.png}}
右側の画面の更新画面を押すと、以下のように、vuexが動く準備ができたようです。
{{:15.vue.jsのvuexでカウンター:pasted:20190126-021146.png}}
===== Counterコンポーネントを作成し,カウンター機能の追加 =====
まずは、vuexを用いない方法で、カウンター機能を作成します。
-カウンターの表示、カウンターの『+1』、『-1』のボタンをcomponents/counter.vueに設置
でいってみたいと思います。
*src/components/Counter.vueの新規作成
{{ count }}
-1
+1
{{:15.vue.jsのvuexでカウンター:pasted:20190126-033930.png}}
*HelloWorldコンポーネントでCounterコンポーネントを表示
src/App.vueの変更
(変更前)
{{:15.vue.jsのvuexでカウンター:pasted:20190126-034149.png}}
(変更後)
{{:15.vue.jsのvuexでカウンター:pasted:20190126-034431.png}}
App.vueとcomponents/Counter.vueを少しだけ変更して、以下のようになった。
{{:15.vue.jsのvuexでカウンター:pasted:20190126-035002.png}}
+1をクリックと数字が1増えて、-1をクリックすると、数字が1減る。
{{:15.vue.jsのvuexでカウンター:pasted:20190126-035108.png}}
次は、上記のカウンターの増減を、Vuexを用いる方法に書き換えていきます。
===== Vuexの説明 =====
Vuexは図のようなデータの流れを持つ,状態管理のパターンです.
-ComponentはdispatchすることでActionsを実行する
-ActionsはCommitすることでMutationsを利用する
-MutationsはStateを変更する
{{:15.vue.jsのvuexでカウンター:pasted:20190126-035541.png}}
Vuexの図:https://vuex.vuejs.org/ja/より引用
これだけでは何のことかさっぱりわかりません。。。
しかし、アプリが複雑になるほど、Vuexは必要になることは間違いないらしいので、やるしかありません!
(Vuexを用いないでデータをやり取りするためには、親コンポーネントと子コンポーネントの間でpropsと$emitのデータのバケツリレーが必要いなるためらしいです。)
今度こそ、上記のカウンターアプリをVuexを用いたアプリにします。
===== カウンター機能にVuexを利用 =====
以下の3つを行う必要があるそうです。(参考:[[https://qiita.com/ferretdayo/items/edcd2b6682148e477104#%E3%82%AB%E3%82%A6%E3%83%B3%E3%82%BF%E3%83%BC%E6%A9%9F%E8%83%BD%E3%81%ABvuex%E3%82%92%E5%88%A9%E7%94%A8|カウンター機能にVuexを利用]])
-src/store.jsファイルを新規作成し,state, actions, mutations, gettersを定義 (済み)
-src/main.jsにstoreファイルに書かれたstoreを登録 (済み)
-CounterコンポーネントからVuexを利用
==== src/store.jsファイルの編集 ====
stateとかactionsとか言葉がたくさん出てきますが、以下を、100回くらい声に出して読んで、写経していくしかなさそうです。。。(参考:[[https://qiita.com/ferretdayo/items/edcd2b6682148e477104#%E3%82%AB%E3%82%A6%E3%83%B3%E3%82%BF%E3%83%BC%E6%A9%9F%E8%83%BD%E3%81%ABvuex%E3%82%92%E5%88%A9%E7%94%A8|カウンター機能にVuexを利用]])
-stateには状態を持ちたい情報を定義する
-actionsでアクションを定義,commitすることでmutationsが実行される
-gettersはコンポーネントがデータを取得する際に利用される
-mutationsはstateの状態を変更する際に利用される
-gettersとmutationsのメソッドの引数には定義したstateが代入される
-actionsのメソッドの引数のcontextにはdispatch,commit,getters,stateを持つオブジェクトが代入される
-引数に{ commit }とすると,commitだけ利用できる.
src/store.jsの変更
(変更前)
{{:15.vue.jsのvuexでカウンター:pasted:20190126-040721.png}}
(変更後)
{{:15.vue.jsのvuexでカウンター:pasted:20190126-041118.png}}
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から利用するとのことです。(参考:[[https://qiita.com/ferretdayo/items/edcd2b6682148e477104#counter%E3%82%B3%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%8D%E3%83%B3%E3%83%88%E3%81%8B%E3%82%89vuex%E3%81%AE%E5%88%A9%E7%94%A8|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
(変更前)
{{:15.vue.jsのvuexでカウンター:pasted:20190126-055107.png}}
(変更後)
{{:15.vue.jsのvuexでカウンター:pasted:20190126-055347.png}}
カウンターの初期値や、+1、-1の状態管理をvuexに移動しても、ちゃんと、カウンターが動くことが確認できました。
{{:15.vue.jsのvuexでカウンター:pasted:20190126-055912.png}}
ここまでのソースコード(CodeSandeboxバージョン)
{{ :15.vue.jsのvuexでカウンター:vue-vuex-counter.zip |}}
===== 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'
])
}
}
(変更前)
{{:15.vue.jsのvuexでカウンター:pasted:20190126-202927.png}}
(変更後)
{{:15.vue.jsのvuexでカウンター:pasted:20190126-203626.png}}
今回のアプリ作成はここまでとなります。
===== 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の簡単なサンプルを作ってみた
→カウンターアプリを作成します。
===== ソースコード =====
ソースコード
https://codesandbox.io/s/l556xq6327
DEMO
https://l556xq6327.codesandbox.io/
===== リンク =====
目次:[[:index.html|このサイトについて]]
前:[[14.vue.jsのvuexで入力フォーム:index.html|14.vue.jsのvuexで入力フォーム]]
次:[[16.vue.jsのvuexでパスワード制限:index.html|16.vue.jsのvuexでパスワード制限]]