Vuex 5つの概念を簡単なサンプルでまとめる

## Vuexの5つの概念（state,getters,mutations,actions,store)についてまとめる

Vuexについて学んだのでBookクラスを作成し使い方を纏めました


今回Stateで保持するクラスの定義

````models/Book.js
let nextId = 1;

class Book{
  constructor(title,read=false) {
    this.id = nextId++
    this.title = title;
    this.read = read
  }
  finish() {
    this.completed = true;
  }
  init() {
    this.completed = false;
  }
}

export default Book;
````


### store
state,getters,mutations,actions,modulesを持つオブジェクト
1つのプロジェクトに1つまで存在し、Vuexで扱うデータはstoreで管理する

###state
データを保持する領域。

````store/index.js
state:{
books:[
new Book("キングダム",true),
new Book("ワンピース"),
new Book("スラムダンク")
}
```
呼び出し
$store.stateでストアから呼び出す。
computedを介す場合はthisをつける


```App.vue

<template>
  <div id="app">
    <ul>
    <template v-for="book in books">
      <li :key="book.id">{{book.title}}:{{book.read ? "読了" : "未読"}}</li>
    </template>
    </ul>
  </div>
</template>

<script>
export default {
  computed:{
    books(){
      return this.$store.state.Books
    }
  }
}
</script>
```
### getters
stateの値を直接更新するのではなく、なんらかの変更を加える場合に使う
メソッドの形で定義。
引数のstateでstateの値を渡す。第二引数のgettersではgetters内のメソッドを渡している。


```store/index.js
getters: {
    readBooks(state) {
      return state.books.filter(book => book.read);
    },
    readBooksCount(state, getters) {
      return getters.readBooks.length;
    }
  }
```

呼び出しはstate同様。
computedを介す場合はthis.$sotre.gettersで呼び出す

```App.vue
<template>
  <div id="app">
   <h2>読み終えた本:{{readCount}}冊</h2> 
   <ul>
    <template v-for="read in readList">
      <li :key="read.id">{{read.title}}</li>
    </template>
    </ul>
  </div>
</template>
<script>
export default {
  computed:{
   readCount(){
     return this.$store.getters.readBooksCount;
   },
   readList(){
     return this.$store.getters.readBooks;
   }
  }
}
</script>
```

## mutations
stateの値はmutationsを使って更新する
ただし同期処理に限る
mutationsの呼び出しは$store.commit("メソッド名","渡す値")と記述し第一引数と一致したmutations内のメソッドを実行する

```store/index.js
mutations: {
    readBook(state, payload) {
      const book = state.books.find(book => book.id === payload.id);
      if (book.read) {
        book.init();
        // Bookクラスのinitを実行してtrueをfalseにしている
      } else {
        book.finish();
        // Bookクラスのfinishを実行してfalseをtrueにしている
      }
    }
  }

```

```App.vue
<template>
<div id="app">
 <ul>
  <template v-for="book in books">
      <li 
      :key="book.id"
      @click="readBook(book.id)"
      >{{book.title}}:{{book.read ? "読了" : "未読"}}</li>
    </template>
 </ul>
</div>
</template>
<script>
export default {
  methods:{
    readBook(id){
      const payload = {id};
      this.$store.commit("readBook",payload)
     //mutationsを使う時はcommitを実行し第1引数の文字列と一致したメソッドを実行
    },
  }
}
</script>
```

### actions
非同期処理を含むstateを更新ができる
mutationsに対しcommitを行い間接的にstateを更新する
$store.dispatch("メソッド名","渡す値")としてactions内のメソッドを呼ぶ
actionsのメソッド内でcommitを実行する事でmutationsを通してstateを更新している。
※contextオブジェクトの中身にはstore.commitが含まれる

```store/index.js
mutations: {
    readBook(state, payload) {
      const book = state.books.find(book => book.id === payload.id);
      if (book.read) {
        book.init();
        // Bookクラスのinitを実行してtrueをfalseにしている
      } else {
        book.finish();
        // Bookクラスのfinishを実行してfalseをtrueにしている
      }
    }
  },
  actions: {
    actionsRead(context, payload) {
      setTimeout(() => {
        context.commit("readBook", payload);
      },1000)
   }
  },
```

```App.vue
<template>
  <div id="app">
    <ul>
    <template v-for="book in $store.state.books">
      <li 
      :key="book.id"
      @click="readBook(book.id)"
      >{{book.title}}:{{book.read ? "読了" : "未読"}}</li>
    </template>
    </ul>
  </div>
</template>
<script>
export default {
  methods:{
    readBook(id){
      const payload = {id};
      this.$store.dispatch("actionsRead",payload)
    }
  }
}
</script>
```
他にもVueインスタンスとstoreの連携にはmapState,mapGetters,mapMutations,mapActionsを使った呼び出し方がある。
参考
https://vuex.vuejs.org/ja/guide/