Vuexの基本

###はじめに

Vuexについて勉強したのでまとめてみます。

公式
https://vuex.vuejs.org/ja/

###Store
Vuexを使う上でアプリケーションの状態（情報）を管理する役割。


###Vuexとは
state management。データ（状態）を管理するもの。
Vuexがない環境ではコンポーネント間のデータの受け渡しには、propsや$emitによるイベントを利用して行います。しかし、コンポーネント間でのデータ受け渡しが頻繁に行われたり階層が増えてくるとporpsやemitでのデータ管理が難しくなる。複雑に構成されたコンポーネントでのデータ管理の難しさを解決するための仕組みがVuexです。Vuexという入れ物にデータを入れることでどのコンポーネントからでもVuex内に保持するデータへのアクセスが可能になります。
Vuexのstateはdataプロパティと同じもの。Vuexのstateにプロパティを追加することですべてのコンポーネントからアクセスが可能となる。Vuexは独立したデータ保管場所。


```store\index.js

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とのやりとりを行う




###state
stateはdataオプションのような存在で、stateが変更されるとコンポーネントの算出プロパティやテンプレートへと反映されます。なんでもstateに情報を保持させるのではなく、コンポーネント内部でしか使わないようなものはこれまでと同様にdataオプションに、アプリケーション全体で管理するものはstore内で管理すると良いです。

###getters
stateから別の値を算出する為に使われる。
gettersは算出プロパティcomputedと同じような働きをしてくれます。
値がキャシュされ、そのgettersが依存しているstateが更新されない限り再評価しません。
違う点は引数にstateと他のgettersを持つことで、それらを使って違う値を返します。
computedと同様に、計算した値を返す以外の処理は行うべきではありません。
computedプロパティだと記述したそのコンポーネント内でしか利用できないので、他のコンポーネントで同じ処理を行いたい場合は同じコードをコンポーネント毎に記述する必要がありまる。でもGettersを利用するとVuexのstoreの中に保存されているので、他のコンポーネントからも同じ方法で利用できます。



getters

```store\index.js
  getters: {
  	users : function(state){
  		return state.users.filter(user => user.age < 30);
  	}
```
computedプロパティ
算出プロパティ(computed)はリアクティブな依存関係にもとづきキャッシュされる.
算出プロパティは、リアクティブな依存関係が更新されたときにだけ再評価されます

```component.js
 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メソッドを使用します。

<br/>
###例
```store\index.js
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(){
        //mutationsをコミット
          context.commit('reducePrice');
      }, 2000);
  }
  }
});
```
ビュー

```vue
<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>
```
<br/>
メソッドでstateを変更するダメなパターン。使ってはダメ。
strictモードにするとError: [vuex] do not mutate vuex store state outside mutation handlers.のエラーが出る。

```vue
<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をコミットするパターン。

```vue
<script>
export default {
  computed: {
      saleProducts() {
      return this.$store.getters.saleProducts
    },
  },
  methods: {
   reducePrice:function(){
   this.$store.commit("reducePrice")
   }
  }
}
</script>
```
actionsをdispatchするパターン。

```vue
<script>
  methods: {
 this.$store.dispatch("reducePrice")
  }
</script>

```

<br/>
<br/>
payloadを使う場合。

```store\index.js

  mutations: {
    reducePrice: (state, payload)=> {
      state.products.forEach(product => {
        product.price -= payload
      });
    }
  },
```

```vue
<script>
  methods: {
   reducePrice:function(amount){
    this.$store.commit("reducePrice",amount)
   }
  }
</script>

```
引数として4を渡す。２ずつ数字が減る。

```vue
 <button v-on:click="reducePrice(4)">Reduce Price</button>
```

同じくpayloadを使う場合。今回はactionsをdispatch。

```vue
<script>
  methods: {
   reducePrice:function(amount){
    this.$store.dispatch("reducePrice",amount)
   }
  }
</script>

```
```store\index.js

  mutations: {
    reducePrice: (state, payload)=> {
      state.products.forEach(product => {
        product.price -= payload
      });
    }
  },
  actions: {
    reducePrice: (context) => {
      setTimeout(function(){ 
          context.commit('reducePrice', payload);
      }, 2000);
  }
  }
```
###双方向算出プロパティ
https://vuex.vuejs.org/ja/guide/forms.html#%E5%8F%8C%E6%96%B9%E5%90%91%E7%AE%97%E5%87%BA%E3%83%97%E3%83%AD%E3%83%91%E3%83%86%E3%82%A3

入力された文字に色を変更します。red→赤。blue→青。

色を変えたいタグにstyle属性追加

```vue
 :style="{color:$store.state.colorCode}"
```
v-modelでcolorCodeを指定

```vue
   <input v-model='colorCode' type="text">
```
stateにcolorCode追加

```store\index.js
   state: {
    colorCode: 'blue'
  },
```
mutationsにsetColorCodeメソッド追加

```store\index.js
   mutations: {
    setColorCode(state,payload) {
      state.colorCode = payload
    }
  },
```

computedプロパティでsetColorCodeにペイロードを渡してsetColorCodeメソッドをcommit

```vue
<script>
   computed: {
  colorCode: {
    get(){
     return this.$store.state.colorCode
    },
    set(colorValue){
   this.$store.commit('setColorCode',colorValue)
    }
  }
}
<script/>
```
<br/>
以上です。