Vuexとは?
Vuexの概念を理解するのがむずかしい・・・
Vuexは状態管理のためのライブラリだと言われている。
よく木に例えられたりするが、自分には合わない説明だったので自分の言葉でまとめたいと思う。
利便性
なぜ、Vuexがあると良いのか、むしろないと困ってしまうのか?ということについて考えてみよう。
例えば、親子関係が複雑なVueプロジェクトがあったとする。この時、あるデータを親から子のコンポーネントへ移す時は propsを使うであろう。しかし、この場合、その構造が複雑になればなるほどほど受け渡しの記述が多くなったり、変更があった時に大変であろう。

もし、この時一貫した情報やメソッドを保持したりする中心的な場所があれば、上記のような構造での記述や受け渡しでのミスを減らすことができる。これがVuexであり、便利なところである。
この store があれば各コンポーネントで取得したい情報や利用したいメソッドを同時に保持することができて、同じ取り出し方で利用することができる。

各プロパティ
この部分が一番理解するのに困る点であろう。なぜなら、各プロパティの機能に加えてそのプロパティを利用するために関連性を持つメソッドも出てきて情報量が多すぎるからだ。まずは細分化して考えて見ていただきたい。
state
これはもうdataプロパティと同じで捉えて良いと考えている。様々なコンポーネントやページで使い共有される情報をプロパティとして state に定義する。
export default new Vuex.Store({
state: {
name:"",
email:"",
password:""
},
getter
state の情報を得るものとして使われる。自分の感覚では算出プロパティに近い扱いである。store に getter を定義すると state の状態変化に基づいてその値を変化させて返す。ここで注意したいのは state の値自体を変化させるものではなく、 state の値をもとに getter で変化させるということだ。値の変更は mutation で行う。
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 である。
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 を用いて呼び出す。
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 -------
<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>
<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>
<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>
<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 メソッドが定義されている。
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("/");
}
}
},
});
ここでログイン成功時にはどんな処理が行われているかまとめてみる

まず、ボタンのクリックでloginメソッドがloginアクションを呼び、そのactionが入力したパスワードとメアドがstateの各値と一致したらauth ミュテーションを呼んで更新するようにしている。
新規登録はこの中でloginアクションのstate.passwordとstate.emailとの整合性確認がないだけである。
一般化
さらに、これを一般化させる。今回はgetter やdiaptch、commitも含めて分析してみる。

やっていることは同じである。
①イベント発火でメソッドが実行させる。
②メソッドがdispatchを通してaction を呼ぶ。
③actionがcommitを通してmutationを呼ぶ。
④mutation がstateを更新させる。
⑤stateに値が保存される。
⑥computed を通してgetterが値の変更を感知して値を変化させる。
だが、これには大きな欠点がある。それはstate がリロードすると値を消失してしまうことである。
具体的には、リロードするとstateから新規登録した値がなくなってしまうため、ログインできなくなってしまうということである。
それを補う役割をするのが localStorage である。
localStorage
localStorage は値をブラウザ上にキーとバリューセットで保存するものである。
以下localStorageに保存、取得、削除させるメソッドである。
localStorage.setItem('キー', '値');//保存
localStorage.getItem('キー');//取得
localStorage.removeItem('キー');//削除
また、localStorageは文字列形式で値が格納されるので、保存前にオブジェクトをJSON形式に変換しなければならない。
逆に、取得したときの値はJSON形式からオブジェクトに戻さなければならない。
JSON.stringify(obj);//オブジェクト→JSON
JSON.parse(getjson);//JSON→オブジェクト
Vuexでの利用
ここでリロードにより値が保存されないのならば、値が保存されるようにlocalStorageを利用しようという考え方である。
以下、localStorage を加えてブラウザ上に値を保存するようにしたバージョンのstoreである。
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
