vue.js入門の7章のタスク管理アプリケーションを写経しながらVuexの勉強をしてみる
ここは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>
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>
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で使う。
- 使いどころはユーザ情報などのコンポーネントを跨いだグローバルなデータ
ということが分かっていればとりあえず良いかな?