Vuexの基本
はじめに
Vuexについて勉強したのでまとめてみます。
Store
Vuexを使う上でアプリケーションの状態(情報)を管理する役割。
Vuexとは
state management。データ(状態)を管理するもの。 Vuexがない環境ではコンポーネント間のデータの受け渡しには、propsや$emitによるイベントを利用して行います。しかし、コンポーネント間でのデータ受け渡しが頻繁に行われたり階層が増えてくるとporpsやemitでのデータ管理が難しくなる。複雑に構成されたコンポーネントでのデータ管理の難しさを解決するための仕組みがVuexです。Vuexという入れ物にデータを入れることでどのコンポーネントからでもVuex内に保持するデータへのアクセスが可能になります。 Vuexのstateはdataプロパティと同じもの。Vuexのstateにプロパティを追加することですべてのコンポーネントからアクセスが可能となる。Vuexは独立したデータ保管場所。
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export default new Vuex.Store({ state: { }, getters: { }, mutations: { }, actions: { } })
state→アプリケーションの状態(情報) getters→stateの一部やstateから返された値を保持する mutations→stateを更新(変化)させる action→非同期通信や外部APIとのやりとりを行う
この4つをまとめたものをモジュールと言います。
state
stateはdataオプションのような存在で、stateが変更されるとコンポーネントの算出プロパティやテンプレートへと反映されます。なんでもstateに情報を保持させるのではなく、コンポーネント内部でしか使わないようなものはこれまでと同様にdataオプションに、アプリケーション全体で管理するものはstore内で管理すると良いです。
getters
stateから別の値を算出する為に使われる。 gettersは算出プロパティcomputedと同じような働きをしてくれます。 値がキャシュされ、そのgettersが依存しているstateが更新されない限り再評価しません。 違う点は引数にstateと他のgettersを持つことで、それらを使って違う値を返します。 computedと同様に、計算した値を返す以外の処理は行うべきではありません。 computedプロパティだと記述したそのコンポーネント内でしか利用できないので、他のコンポーネントで同じ処理を行いたい場合は同じコードをコンポーネント毎に記述する必要がありまる。でもGettersを利用するとVuexのstoreの中に保存されているので、他のコンポーネントからも同じ方法で利用できます。
getters
getters: { users : function(state){ return state.users.filter(user => user.age < 30); }
computedプロパティ 算出プロパティ(computed)はリアクティブな依存関係にもとづきキャッシュされる. 算出プロパティは、リアクティブな依存関係が更新されたときにだけ再評価されます
computed:{ users: function(){ return this.$store.state.users.filter(user => user.age < 30); } }
↑2つとも同じ結果になる。
mutations
mutations は state を更新する関数を登録します。 stateの更新を行うためには、mutationsを使う必要があります。 mutations はcommit 関数を使って発火させる。 実際に Vuex のストアの状態を変更できる唯一の方法は、mutationsをコミットすることです。 原則として、mutation以外でstateの更新を行うことを禁止。 commitにはpayloadで値を渡すことができる。
actions
actionsは、状態を変更するのではなく、mutationsをコミットします。 アクションは任意の非同期処理を含むことができます。 mutationsを実行するのはcommitですが、actionsを実行するためにはdispatchメソッドを使用します。
例
import Vue from 'vue'; import Vuex from 'vuex'; Vue.use(Vuex); export const store = new Vuex.Store({ strict: true, state: { products: [ {name: 'Banana', price: 20}, {name: 'Orange', price: 40}, {name: 'Apple', price: 60}, {name: 'Rice', price: 80} ] }, getters: { saleProducts: (state) => { let saleProducts = state.products.map( product => { return { name: '**' + product.name + '**', price: product.price / 2, }; }); return saleProducts; } }, mutations: { reducePrice: (state)=> { state.products.forEach(product => { product.price -= 1 }); } }, actions: { reducePrice: context => { setTimeout(function(){ context.commit('reducePrice'); }, 2000); } } });
ビュー
<template> <div id="product-list-one"> <h2>Product List One</h2> <ul> <li v-for="product in saleProducts"> <span class="name">{{ product.name }}</span> <span class="price">£{{ product.price }}</span> </li> </ul> <button v-on:click="reducePrice">Reduce Price</button> </div> </template>
メソッドでstateを変更するダメなパターン。使ってはダメ。
strictモードにするとError: [vuex] do not mutate vuex store state outside mutation handlers.のエラーが出る。
<script> export default { computed: { saleProducts() { //gettersのsaleProductsのデータを取得 return this.$store.getters.saleProducts }, }, methods: { reducePrice:function(){ this.$store.state.products.forEach(product => { product.price -= 1 }); } } } </script>
メソッドでmutationsをコミットするパターン。
<script> export default { computed: { saleProducts() { return this.$store.getters.saleProducts }, }, methods: { reducePrice:function(){ this.$store.commit("reducePrice") } } } </script>
actionsをdispatchするパターン。
<script> methods: { this.$store.dispatch("reducePrice") } </script>
payloadを使う場合。
mutations: { reducePrice: (state, payload)=> { state.products.forEach(product => { product.price -= payload }); } },
<script> methods: { reducePrice:function(amount){ this.$store.commit("reducePrice",amount) } } </script>
引数として4を渡す。2ずつ数字が減る。
<button v-on:click="reducePrice(4)">Reduce Price</button>
同じくpayloadを使う場合。今回はactionsをdispatch。
<script> methods: { reducePrice:function(amount){ this.$store.dispatch("reducePrice",amount) } } </script>
mutations: { reducePrice: (state, payload)=> { state.products.forEach(product => { product.price -= payload }); } }, actions: { reducePrice: (context) => { setTimeout(function(){ context.commit('reducePrice', payload); }, 2000); } }
以上。
参考
6 Hour Vue.js & Firebase Project - FireBlogs - YouTube
Vuex Tutorial #6 - Mutations - YouTube
【Vuex】ストアの4つの概念まとめ【唯一の情報源】 https://qiita.com/kouki-iwahara/items/1a75daaa93657b0b56d7
入門者必読、vue.jsの状態管理Vuexがわかる https://reffect.co.jp/vue/understaind-vue-basic
VueとVuexの間の値の連携の仕方 https://qiita.com/yuyasat/items/ec439bfdc078da5f4122