Vuexの状態管理 is not  情報の永続保存ではないということ

#Vuexとは？
Vuexの概念を理解するのがむずかしい・・・
Vuexは状態管理のためのライブラリだと言われている。
よく木に例えられたりするが、自分には合わない説明だったので自分の言葉でまとめたいと思う。

##利便性
なぜ、Vuexがあると良いのか、むしろないと困ってしまうのか？ということについて考えてみよう。
例えば、親子関係が複雑なVueプロジェクトがあったとする。この時、あるデータを親から子のコンポーネントへ移す時は `props`を使うであろう。しかし、この場合、その構造が複雑になればなるほどほど受け渡しの記述が多くなったり、変更があった時に大変であろう。
![props.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/926931/50d822c3-66ee-7e9f-dd0e-dcfbd047291a.png)
もし、この時一貫した情報やメソッドを保持したりする中心的な場所があれば、上記のような構造での記述や受け渡しでのミスを減らすことができる。これがVuexであり、便利なところである。
この `store` があれば各コンポーネントで取得したい情報や利用したいメソッドを同時に保持することができて、同じ取り出し方で利用することができる。
![props.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/926931/e0ec1f1e-9fc5-f73b-6080-df5110f635c5.png)

##各プロパティ
この部分が一番理解するのに困る点であろう。なぜなら、各プロパティの機能に加えてそのプロパティを利用するために関連性を持つメソッドも出てきて情報量が多すぎるからだ。まずは細分化して考えて見ていただきたい。
###state
これはもうdataプロパティと同じで捉えて良いと考えている。様々なコンポーネントやページで使い共有される情報をプロパティとして `state` に定義する。

```javascript:index.js
export default new Vuex.Store({
  state: {
    name:"",
    email:"",
    password:""
  },
```
###getter
`state` の情報を得るものとして使われる。自分の感覚では算出プロパティに近い扱いである。`store` に `getter` を定義すると `state` の状態変化に基づいてその値を変化させて返す。ここで注意したいのは `state` の値自体を変化させるものではなく、 `state` の値をもとに `getter` で変化させるということだ。値の変更は `mutation` で行う。

```javascript:index.js
const store = new Vuex.Store({
  state: {
    todos: [
      { id: 1, text: '...', done: true },
      { id: 2, text: '...', done: false }
    ]
  },
  getters: {
    doneTodos: state => {
      return state.todos.filter(todo => todo.done)
    }
  }
})
```
###mutation
`mutation` は唯一`state` の値を変更させる方法と公式には言われているが、自分の中では`state`を更新するセッターと捉えている。第一引数に元の状態である `state` を持って第二引数に更新情報となる `payload` を用いてその結果で`state`の値を更新させる。また、この`mutation` を呼び出すときに使うのが `commit` である。

```javascript:index.js
const store = new Vuex.Store({
  state: {
    count: 1
  },
  mutations: {
    increment (state) {
      // 状態を変更する
      state.count++
    }
  }
})
// ...コミットで呼び出す
store.commit('increment', 10)
```
###action
`action` は`mutation` の呼び出し役かつ関数処理の役割があると考えている。非同期処理をかけるのが `mutation` との違いであり、処理は`action` 、`mutation` でその変更を `state` に保存するという役割の分け方が公式の意向にも沿っており良いと思われる。
またコンポーネント側からは `dispatch` を用いて呼び出す。

```javascript:index.js
new Vuex.Store({
  state: {
      amount: 0
  },
  mutations: {
      tax (state, totalPrice) {
          state.amount = totalPrice % 10;
      },
  },
  actions: {
      calPrice (context,num) {
          price = axios.get(リクエストURL);
          totalPrice = price * num;
          context.commit('tax', totalPrice);
      },
  },
}
// ...ディスパッチで呼ぶ
$store.dispatch('calPrice');
```

##新規登録とログイン処理
このVuexの処理の流れを掴むために新規登録とログイン処理を簡易的に作ってみた。
処理の流れとしては新規登録をすると、myPage.vueでユーザー情報を確認できる。ログインをして成功するとmuPage.vueでユーザー情報を確認できる。失敗すると、myPage.vueには遷移できないというものだ。

```
App.vue -----register.vue ----- myPage.vue
       \                      /
        -----login.vue -------
```

```javascript:App.vue
<template>
<div id="app">
  <div class="flex">
    <p @click="$router.push('/register')">新規登録</p>
    <p @click="$router.push('/login')">ログイン</p>
  </div>
  <router-view></router-view>
</div>
</template>

<style>
  .flex {
    display: flex;
    justify-content: space-between;
    margin: 0 auto;
    width: 50%;
  }
  .card {
    margin: 100px auto;
    width: 350px;
    
    border-radius: 5px;
    padding: 20px;
  }
  .form {
    display: flex;
    flex-direction: column;
  }
  button {
    margin: 0 auto;
    width: 50%;
  }
</style>
```
```javascript:pages/register.vue
<template>
  <div>
    <div class="card">
      <div class="form">
        <input placeholder="ユーザーネーム" type="text" v-model="name" />
        <input placeholder="メールアドレス" type="email" v-model="email" />
        <input placeholder="パスワード" type="password" v-model="password" />
        <button @click="register">新規登録</button>
      </div>
    </div>
  </div>
</template>
<script>
export default {
  data() {
    return {
      name: "",
      email: "",
      password: "",
      userInfo:[]
    }
  },
  methods: {
    register() {
      const userInfo = {
        name: this.name,
        email: this.email,
        password: this.password
      }
      this.$store.dispatch("register",userInfo).then(() => {
          this.$router.push({path:'myPage'})
        }
      );
    }
  }
}
</script>

```
```javascript:pages/Login.vue
<template>
  <div>
    <div class="card">
      <div class="form">
        <input placeholder="メールアドレス" type="email" v-model="email" />
        <input placeholder="パスワード" type="password" v-model="password" />
        <button @click="auth">ログイン</button>
      </div>
    </div>
  </div>
</template>
<script>
export default {
  data() {
    return {
      email: "",
      password: "",
      loginInfo:[]
    }
  },
  methods: {
    auth() {
      const loginInfo = {
        email: this.email,
        password: this.password
      }
      this.$store.dispatch("login",loginInfo).then(() => {
        this.$router.push({path:'myPage'})
      });
    }
  }
}
</script>

```
```javascript:myPage.vue
<template>
  <div id="app">
    <p>{{$store.state.name}}</p>
    <p>{{$store.state.email}}</p>
    <p>{{$store.state.password}}</p>
  </div>
</template>
```
`store` 内にはユーザー情報のために`name` `email` `passwprd` といった`state` を用意している。 `mutation` には値の更新のための `signUp` `auth` メソッド、`action` にはそれらを呼び出すための `register` ,`login` メソッドが定義されている。

```javascript:store/index.js
import Vue from "vue";
import Vuex from "vuex";

Vue.use(Vuex);

export default new Vuex.Store({
  state: {
    name:"",
    email:"",
    password:""
  },
  mutations: {
    signUp(state, payload) {
      state.name = payload.name;
      state.email = payload.email;
      state.password = payload.password;
    },
    auth(state,payload) {
      state.email = payload.email;
      state.password = payload.password;
    }
    
  },
  actions: {
      register({ commit }, userInfo ){
        commit("signUp", userInfo);
        
      },
      login({ commit, state },  loginInfo ) {
        if( state.password === loginInfo.password) {
          commit("auth",loginInfo );
          console.log("成功");
        } else {
          this.router.push("/");
        }
    }
  },
});
```
ここでログイン成功時にはどんな処理が行われているかまとめてみる
![ライフ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/926931/c774d881-f9fe-c704-f299-2656db55d3de.png)
まず、ボタンのクリックでloginメソッドがloginアクションを呼び、その`action`が入力したパスワードとメアドが`state`の各値と一致したら`auth` ミュテーションを呼んで更新するようにしている。
新規登録はこの中でloginアクションの`state.password`と`state.email`との整合性確認がないだけである。

これを実際のコードで順番に合わせるとこのようになる。
![MacBook Pro - 1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/926931/b448e807-1917-b4bf-05ce-11a575a2c431.png)

##一般化
さらに、これを一般化させる。今回は`getter` や`diaptch`、`commit`も含めて分析してみる。

![ライフ2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/926931/c5bab5a6-eefa-e33f-1f3d-8daaa29ff627.png)
やっていることは同じである。
①イベント発火でメソッドが実行させる。
②メソッドが`dispatch`を通して`action` を呼ぶ。
③`action`が`commit`を通して`mutation`を呼ぶ。
④`mutation` が`state`を更新させる。
⑤`state`に値が保存される。
⑥`computed` を通して`getter`が値の変更を感知して値を変化させる。
***
だが、これには<font color="red">**大きな欠点**</font>がある。それは`state` がリロードすると値を消失してしまうことである。
具体的には、リロードすると`state`から新規登録した値がなくなってしまうため、ログインできなくなってしまうということである。
それを補う役割をするのが `localStorage` である。

##localStorage
`localStorage` は値をブラウザ上にキーとバリューセットで保存するものである。
以下localStorageに保存、取得、削除させるメソッドである。

```javascript
localStorage.setItem('キー', '値');//保存
localStorage.getItem('キー');//取得
localStorage.removeItem('キー');//削除
```
また、localStorageは文字列形式で値が格納されるので、保存前にオブジェクトをJSON形式に変換しなければならない。
逆に、取得したときの値はJSON形式からオブジェクトに戻さなければならない。

```javascript
JSON.stringify(obj);//オブジェクト→JSON
JSON.parse(getjson);//JSON→オブジェクト
```
##Vuexでの利用
ここでリロードにより値が保存されないのならば、値が保存されるように`localStorage`を利用しようという考え方である。
以下、`localStorage` を加えてブラウザ上に値を保存するようにしたバージョンの`store`である。

```javascript:store/index.js
import Vue from "vue";
import Vuex from "vuex";

Vue.use(Vuex);

export default new Vuex.Store({
  state: {
    name:"",
    email:"",
    password:""
  },
  mutations: {
    signUp(state, payload) {
      state.name = payload.name;
      state.email = payload.email;
      state.password = payload.password;
    },
    auth(state,payload) {
      state.email = payload.email;
      state.password = payload.password;
    }
    
  },
  actions: {
      register({ commit }, userInfo ){
        var setUser = JSON.stringify(userInfo);
        localStorage.setItem('setUser', setUser);
        commit("signUp", userInfo);
        
      },
      login({ commit, state },  loginInfo ) {
        var jsonObj = localStorage.getItem('setUser');
        var jsPar = JSON.parse(jsonObj);
        if(state.password === jsPar.password && state.email === jsPar.email) {
          console.log("成功");
        }else {
          this.router.push("/");
        }
    }
  },
});
```

`actions`の`login`と`register`メソッドで上記のメソッドを用いている。
`register` では`localStorage`に保存し、`login`では`localStorage`からキーで保存したオブジェクトを取り出してその値と`state`の値の整合性を確認している。
処理としては以前の`index.js`と同じである。

##まとめ
前提であるVuexの説明がメインとなってしまったが、リロードでVuexが情報を保存するのではなく状態管理のためのライブラリであるということが理解できたであろう。

そのため、実践的にはリロードすることを前提として`localStorage`などに保存することが多いだろう。また、Vue.jsではわざわざこの`localStorage` を利用せずとも`vuex-persistedstate`というライブラリで自動的に保存する機能がある。
また次の機会にこのライブラリを用いてVuexを用いた情報の永続保存について実践していきたいと思う。

###参考
https://vuex.vuejs.org/ja/
https://youtu.be/9Lht5mZ9zxw
https://youtu.be/tf6HWsyAVv4