はじめに
最近仕事でVuexを理解する必要が出てきたので、自分の理解のためにメモしておきます。
Vuexとは
VuexはVue.jsにおいて、データの受け渡しを便利してくれるライブラリ。
通常のVue.jsでは、データを他のコンポーネントに渡す際にprops
や$emit
を使います。コンポーネント数が少ない場合はこれでも大丈夫なのですが、コンポーネント数が増えたり、階層が深くなると、素のVue.jsではデータの管理が難しくなってしまいます。
そんなデータ管理の難しさを解消してくれるのがVuexです。今回は以下の点について説明してあります。
- state
- getters
- mutations
- actions
Vuexを触ってみる
state
を使ってみる
以下でプロジェクト作成、Vuexインストール後にlocalhost:8080にアクセスしてサンプル画面がでていることを確認します。
% vue create vuex-demo
% cd vuex-demo
% npm install vuex
% npm run serve
まずは、Vuexを使うための設定をmain.js
に記述します。
import { createApp } from "vue";
import App from "./App.vue";
import store from '../store' // vuexを使う設定
const app = createApp(App)
app.use(store) //vuexを使う設定
app.mount('#app')
storeを使うための記述をvuex-demo/store/index.js
に追記します。
import { createStore } from "vuex";
export default createStore({
state: {
message: 'Hello Vuex!'
}
});
最後にvueファイルにstoreで定義したメッセージを呼び出してみます。
呼び出し方はthis.$store.state.~
です。
<template>
<div id="app">
<h1>{{ this.$store.state.message }}</h1>
</div>
</template>
<script>
export default {
name: 'app',
}
</script>
store.stateにメッセージを記述することで、他のコンポーネントでもmessage
を参照したいときはApp.vue
と同じように書けばよいのです。それを確認します。
App.vue
ではなくcomponents
配下にファイルを作成し、this.$store.state.message
を追記し、画面に同じメッセージが表示されることを確認します。
<template>
<h2>{{ this.$store.state.message }}</h2>
</template>
<script>
export default ({
name: 'sampleContents',
})
</script>
App.vue
も追記をしていきます。
<template>
<div id="app">
<h1>{{ this.$store.state.message }}</h1>
<sampleContents></sampleContents>
</div>
</template>
<script>
import sampleContents from './components/contents.vue'
export default {
name: 'app',
components: {
sampleContents
}
}
</script>
画面は以下のようになるはずです。stateファイルで同じ内容のmessage
を参照できることがわかると思います。
getters
を使ってみる
storeの状態を算出するために使うのがgetters
です。下のように書くことで条件による絞り込みを行うことができます。computed
的なことを実行することができるものです。
import { createStore } from "vuex";
export default createStore({
state: {
message: 'Hello Vuex!',
// gettersのためにデータを追加
todos: [
{id: 1, text: 'Learn Vuex', done: true},
{id: 2, text: 'Learn Vue.js', done: false},
{id: 3, text: 'Learn Python', done: true},
{id: 4, text: 'Learn Node.js', done: false},
{id: 5, text: 'Learn Julia', done: true}
]
},
// gettersを追加!
getters: {
// 何の変哲ものない書き方?
doneTodos (state) {
return state.todos.filter(todo => todo.done)
},
// プロパティスタイルアクセスの書き方
doneTodosCount (state, getters) {
return getters.doneTodos.length
},
// メソッドスタイルアクセスの書き方
getTodoById: (state) => (id) => {
return state.todos.find(todo => todo.id === id);
}
}
});
呼び出し方は
<template>
<h2>{{ this.$store.state.message }}</h2>
<h3>all todo </h3>
<li v-for="todo in $store.state.todos" v-bind:key="todo.id">
{{ todo }}
</li>
<h3>done todos is</h3>
<li v-for="doneTodo in doneTodos" v-bind:key="doneTodo.id">
{{ doneTodo }}
</li>
<p>count is {{ doneTodosCount }}</p>
<p>id=2 todo is {{ getTodoById }}</p>
</template>
<script>
import { mapGetters } from "vuex";
export default ({
name: 'sampleContents',
computed: {
// mapGettersを使って読み込むことや
...mapGetters({
doneTodos: 'doneTodos',
doneTodosCount: 'doneTodosCount',
}),
// 下記のような方法で読み込むことも可能
getTodoById () {
return this.$store.getters.getTodoById(2);
}
},
})
</script>
mutation
を使ってみる
index.js
がどんどん大きくなってくるので、該当部分だけ抜き出します。
mutationはstateの状態を変えることができます。例えば、新しくToDoリストを追加することができます。
...
mutations: {
addTodo (state, todo) {
state.todos.push( todo );
}
}
...
mutationが実行されるためにはcommit
がトリガーになります。
つまり、commit
がないことにはstateの状態を変えることができません。
<template>
...
<form @submit.prevent="addTodo">
<input
type="text"
v-model="text"
/>
<button>Add ToDo</button>
</form>
...
</template>
<script>
...
methods: {
addTodo () {
// commitを使うことでstoreのtodoの状態を変えることができる
this.$store.commit('addTodo', {
"id": this.$store.state.todos.length + 1,
"text": this.text,
"done": false
});
this.text = '';
},
...
</script>
action
を使ってみる
actionはmutationと似ていますが、以下のような特徴があります。
- 状態の変更するのではなく、mutationのcommitを行なっている
- mutationと違い、非同期処理を含むことができる
mutationと違って、条件によって特定の処理を入れることができます。今回はidを設定できるようにします。
...
actions: {
addTodoSpecifingId ({commit}, number) {
commit('addTodo', {id: number, text: 'Learn Linux', done: false});
}
}
<template>
...
<h2>Add Todo by Actions</h2>
<form @submit.prevent="addDoneTodo">
<input
type="integer"
v-model="specific_id"
/>
<button>Add ToDo by actions</button>
</form>
...
</template>
<script>
...
methods: {
...
addDoneTodo () {
// actionはdispatchによって呼び出される
this.$store.dispatch('addTodoSpecifingId', this.specific_id)
},
...
</script>
最後に
書きながらまとめることでなんとなくVuexを理解できた気がする。
公式が言っていた「状態管理パターン」の意味はstate, getter, mutation, actionがわかれば完璧ですね。