Edited at

Reactユーザ必見!! Vuexの概念を学ぶ


概要


  • 普段Reactを使っていて、Vueも学ばないといけない

  • Vueは分かるけどVuexはよく分からない

って方の助けに成ればと思います。


読んでもらいたいポイント


  • Vueに必要なツール 

  • VueとVuexによるデータの流れ 

  • ゲッター(Getter) *

  • ストアとコンポーネント間の通信 *

  • ストアにアクセスするコンポーネントを絞る *


Vueに必要なツール

まず、Chromeの拡張ツールで、vue-devtoolsを導入しましょう。

次に、VS Codeを使っている人は拡張機能で Vetur を入れましょう。


Vuexの4大項目

項目名
大まかな概要

state
状態のことです 

getters
stateをコンポーネントに渡す役割を持っています

mutations  
stateを変更する役割を持っています。

actions
非同期通信やlocalStorageやAPI, BackEndとの通信などをします。


VueとVuexによるデータの流れ


  1. componentからactionを発火。

  2. actionをcommitし、mutationを発火。

  3. mutationによってstateの状態を変更します。

  4. gettersによって、componentにstateの状態を渡す。


Vuex

Vueにおける状態管理(ReactでいうRedux)です。

内部的にPromiseを採用しています。


store/index.js

import Vue from 'vue';

import Vuex from 'vuex';
import users from './users';

Vue.use(Vuex); // Vuexを使うことを宣言します

// ストアを作成する
const store = new Vuex.Store({

// モジュールを分割することによって管理しやすくします。
modules: {
users,
}
});

export default store;



Vuex周りのこと


モジュール(module)

一つのストアオブジェクトにstate, getters, mutation, actionを記述していく場合、管理するのが大変になるため、ストアをモジュールに分割します。

モジュールのmutationやgettersの中で渡される第一引数は、モジュールのローカルステートです。


アクション(action)


  • ReactでいうActionです。

  • mutationに対してcommitすることによって、mutationを発火できます。

  • 非同期的な処理やAPI, BackEndとの通信はactionで行います。

actionは、commit(Reactでいうdispatch)という命令をmutationにします。


store/users/actions.js

import * as types from './mutationType';

export default {
addUser({ commit }, value) {
// commit(mutation, 値);
commit(types.createUser, value);
}
}



コンポーネントでactionを使う


Top.vue

<template>

<div>
<form
@submit.prevent="addUser(form)"
style="padding: 32px 20px"
>
ID: <input type="text" >
名前: <input type="text" >
年齢: <input type="text" >
<input type="submit">
</form>

<table border="1">
<tr>
<th>ID</th>
<th>Name</th>
<th>Age</th>
</tr>
            <!-- for文です -->
<tr
v-for="(user, index) in users"
:key="index"
>
<td>{{ user.id }}</td>
<td>{{ user.name }}</td>
<td>{{ user.age }}</td>
</tr>
</table>
</div>
</template>

<script>
import { mapGetters, mapActions } from 'vuex';

export default {
name: 'Top', // vue devtoolsで表示されるコンポーネント名です。
// 使う値を定義します。
data () {
return {
users: '',
form: {
id: '',
name: '',
age: ''
}
};
},

// 算出関数を定義します
// computedでは、returnを必ず返すようにしないといけません。
// Vueでよく使われる機能の1つです。
computed: {
// mapGettersは、computedで定義します。
// mapGetters("名前空間名", ["gettersで定義した関数名"]
...mapGetters('users', [
"getUsers",
"getUser"
])
},

// vueインスタンスが作成された時に、発火します。
created () {
this.users = this.getUsers; // 下の書き方でもかけますが、オススメできません。
},

// methodsはeventや処理をする関数を定義します。
// Vueでよく使われる機能の1つです。
methods: {
// mapActions("名前空間名", ["actionsで定義した関数名"])
...mapActions("users", ["addUser"])
}
}
</script>



ミューテーションタイプ (mutation-type)

ReactでいうActionTypeです。


store/users/mutationType.js

export const createUser = "createUser";



ミューテーション(mutation)


  • ReactでいうReducerの役割で、stateの状態を変更する唯一の方法です。Vuexでは原則としてmutation以外がstateの更新を行うことを禁止しています。

  • mutationでは、なるべくstateの値を変更するだけにします。また、同期的な処理のみになります。

  • コンポーネント側から直接mutationを発火させて、stateの状態を変更させるのではなく、actionを通じてmutationを発火させた方がいいと思います。


store/users/mutations.js

import * as types from 'mutationType';

export default {
// stateは、参照渡しです。 
// 元の値をコピーではなく、stateの値を直接変更します。
[types.createUser] (state, payload) {
state.users.push(payload);
}
}



ゲッター(getter)


  • stateの状態を算出したい時や、コンポーネント側にstateの状態を渡したい時に使います。

  • Reactにはない概念だと思います。


store/users/getters.js

export default {

getUsers: state => {
return state.users;
},
getUser: state => id => {
const user = state.users.filter(user => {
return user.id === id
});
return user;
}
}


gettersをコンポーネント側で扱う


Top.vue

<template>

<div>
<table border="1">
<tr>
<th>ID</th>
<th>Name</th>
<th>Age</th>
</tr>
            <!-- for文です -->
<tr
v-for="(user, index) in users"
:key="index"
>
<td>{{ user.id }}</td>
<td>{{ user.name }}</td>
<td>{{ user.age }}</td>
</tr>
</table>
</div>
</template>

<script>
import { mapGetters } from 'vuex';

export default {
name: 'Top', // vue devtoolsで表示されるコンポーネント名です。
// 使う値を定義します。
data () {
return {
users: []
};
},

// 算出関数を定義します
// computedでは、returnを必ず返すようにしないといけません。
// Vueでよく使われる機能の1つです。
computed: {
// mapGettersは、computedで定義します。
// mapGetters("名前空間名", ["gettersで定義した関数名"]
...mapGetters('users',
"getUsers",
"getUser"
])
},
// vueインスタンスが作成された時に、発火します。
created () {
this.users = this.getUsers;
}
}
</script>



ステート(state)

一部のコンポーネントでしか使用しないデータは、コンポーネントのdataオプションで管理し、アプリケーション全体で使用されるデータはストア内で管理するようにします。


store/users/index.js

import getters from './getters';

import mutations from './mutations';
import actions from './actions';

export default {
// 名前空間を分けます。modulesで定義した名前空間で分けられます。
// この場合だと、"user"という名前空間で分けられます。
// デフォルトでは、全て同一の名前空間に登録されます。
namespaced: true,

// 状態を定義します。
state: {
users: [
{ id: 1, name: "hoge", age: 15},
{ id: 2, name: "あああ", age: 23 },
]
},
getters,
mutations,
actions
}



ディレクトリ構成

store [Directory]

- index.js
- mutationType.js
users [Directory]
- index.js
- mutations.js
- getters.js
- actions.js


ストアとコンポーネント間の通信


  • this.$storeによるアクセス

this.$storeにはルートのコンポーネントのstoreオプションに渡されたストアのインスタンスが入っており、ステートの取得や、アクション、ミューテーションの実行などを 直接 行うことができます。

何度もthis.$storeと書いたり、直接変更などを行えるためあまりオススメできません。


  • ヘルパー関数によるアクセス

コンポーネントからストアを使うために用意されているヘルパー関数として、mapState, mapGetters, mapMutations, mapActionsがあります。

これらのヘルパー関数で、ステート、ゲッター、ミューテーション、アクションをコンポーネントの算出プロパティ・メソッドと結びつけられます。

こちらはストアのステート、ゲッター、ミューテーション、アクションをコンポーネント側に流し込むイメージです。


ストアにアクセスするコンポーネントを絞る

ReactのようにContainer Component(ロジックなどの処理があるコンポーネント)とPresentational Component(表示コンポーネント)に分けて、Container Componentからpropsを通してPresentational Componentに値を渡すようにすることで、変更に強くなります。


まとめ

この記事を通してVueやVuexについて、理解してくれた方や興味を持ってくれた方がいたら嬉しいです。

記事を書いてみて、うまく表現できない部分や説明が難しい部分があってVueについて、もっと勉強しないといけないなと思いました。


参考にさせて頂いたサイト

https://medium.com/studist-dev/ddd-vuex-c47055f6c1ba