#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