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は独立したデータ保管場所。

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