vue.js入門の7章のタスク管理アプリケーションを写経しながらVuexの勉強をしてみる
- App.vueのtemplate部分
ここはVuexを使わない場合と何も変わらない。ディレクティブでVueインスタンスに指示を送っているだけ。
<template> <div id="app"> <h2>タスク一覧</h2> <ul> <li v-for="task in tasks" v-bind:key="task.id"> <input type="checkbox" v-bind:checked="task.done" v-on:change="toggleTaskStatus(task)"> {{ task.name }} - <span v-for="id in task.labelIds" v-bind:key="id"> {{ getLabelText(id) }} </span> </li> </ul> <form v-on:submit.prevent="addTask"> <input type="text" v-model="newTaskName" placeholder="新しいタスク"> </form> <h2>ラベル一覧</h2> <ul> <li v-for="label in labels" v-bind:key="label.id"> <input type="checkbox" v-bind:value="label.id" v-model="newTaskLabelIds"> {{ label.text }} </li> </ul> <form v-on:submit.prevent="addLabel"> <input type="text" v-model="newLabelText" placeholder="新しいラベル"> </form> <h2>ラベルでフィルタ</h2> <ul> <li v-for="label in labels" v-bind:key="label.id"> <input type="radio" v-bind:checked="label.id === filter" v-on:change="changeFilter(label.id)"> {{ label.text }} </li> <li> <input type="radio" v-bind:checked="filter == null" v-on:chenge="changeFilter(null)"> フィルタしない </li> </ul> <h2>保存と復元</h2> <button type="button" v-on:click="save">保存</button> <button type="button" v-on:click="restore">復元</button> </div> </template>
- App.vueのscriptタグ内
script部分のcomputed、method部分でVuexのstoreに対するデータの取得、更新処理を書いている。更新部分にcommitとdispatchの2パターンがあるのがややこしいけど
- ミューテーション(通常のstate更新)を行う際はcommit
- アクション(非同期処理や外部APIとのやり取り)を行う際はdispatch
と分けて使う。ゲッター(stateの取得処理)とミューテーションを基本的には使ってカバーできないものをアクションで実装するらしい。
<script> export default { data () { return { newTaskName: '', newTaskLabelIds: [], newLabelText: '' } }, computed: { tasks () { return this.$store.getters.filteredTasks }, labels () { return this.$store.state.labels }, filter () { return this.$store.state.filter } }, methods: { addTask () { this.$store.commit('addTask', { name: this.newTaskName, labelIds: this.newTaskLabelIds }) this.newTaskName = '' this.newTaskLabelIds = [] }, toggleTaskStatus (task) { this.$store.commit('toggleTaskStatus', { id: task.id }) }, addLabel () { this.$store.commit('addLabel', { text: this.newLabelText }) this.newLabelText = '' }, getLabelText(id) { const label = this.labels.filter(label => label.id === id)[0] return label? label.text : '' }, changeFilter (labelId) { this.$store.commit('changeFilter', { filter: labelId }) }, save () { this.$store.dispatch('save') }, restore () { this.$store.dispatch('restore') } } } </script>
- Vuexのstore部分
storeはstate(アプリケーションの状態)を管理する部分でこれがVuexの根幹。
Vueインスタンスにdataやmethods、computedなどのoptionを書いていくのと同じような感じでstate(Vueインスタンスのdataのようなもの)と上記のgetters、mutations、actionsを書いていく。
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) const store = new Vuex.Store({ state: { tasks: [ { id: 1, name: '牛乳を買う', labelIds: [1, 2], done: false }, { id: 2, name: 'Vue.jsの本を買う', labelIds: [1, 3], done: true } ], labels: [ { id: 1, text: '買い物' }, { id: 2, text: '食料' }, { id: 3, text: '本' } ], nextTaskId: 3, nextLabelId: 4, filter: null }, getters: { filteredTasks (state) { if(!state.filter) { return state.tasks } return state.tasks.filter(task => { return task.labelIds.indexOf(state.filter) >= 0 }) } }, mutations: { addTask (state, { name, labelIds }) { state.tasks.push({ id: state.nextTaskId, name, labelIds, done: false }) state.nextTaskId++ }, toggleTaskStatus (state, { id }) { const filtered = state.tasks.filter(task => { return task.id === id }) filtered.forEach(task => { task.done = !task.done }) }, addLabel (state, { text }) { state.labels.push({ id: state.nextLabelId, text }) state.nextLabelId++ }, changeFilter (state, { filter }) { state.filter = filter }, restore(state, { tasks, labels, nextTaskId, nextLabelId }) { state.tasks = tasks state.labels = labels state.nextTaskId = nextTaskId state.nextLabelId = nextLabelId } }, actions: { save ({ state }) { const data = { tasks: state.tasks, labels: state.labels, nextTaskId: state.nextTaskId, nextLabelId: state.nextLabelId } localStorage.setItem('task-app-data', JSON.stringify(data)) }, restore ({ commit }) { const data = localStorage.getItem('task-app-data') if (data) { commit('restore', JSON.parse(data)) } } } }) export default store
あとはstoreのモジュール分割やRouterとの連携などもVue.js入門のこの後のページで記載されているが、Vuexの基本的なところは
- Vueインスタンスのdataで保持していた部分をstoreのstateに切り出してgetter、computed、actionで使う。
- 使いどころはユーザ情報などのコンポーネントを跨いだグローバルなデータ
ということが分かっていればとりあえず良いかな?