HTML5テクニカルノート
Vue.js + Vuex入門 06: チェックした項目をまとめて削除する
- ID: FN1910005
- Technique: HTML5 / ECMAScript 2015
- Library: Vue.js 2.6.10
単一ファイルコンポーネントにVuexのStoreを加えてつくるTodoMVCアプリケーションのチュートリアルシリーズ「Vue.js + Vuex入門」の第6回で新たに加えるのは、チェック済みの項目をまとめてリストデータから除くボタンです。さらに、Storeのmutations
に送るcommit()
をmethods
に定める、ヘルパー関数mapMutations()
も使ってみます。
01 チェック済みの項目をすべて削除する
新しい削除ボタンは、フッタのコンポーネントsrc/components/TodoController.vue
にぎのように加えましょう。click
イベントのリスナーメソッド(removeCompleted()
)からcommit()
で呼び出すのは、モジュールsrc/store.js
のmutations
に新たに定めた同名のメソッド(removeCompleted()
)です。未処理項目のフィルタメソッド(filters.active()
)で取り出した項目データを、もとのリストデータ(todos
)に上書きしています。
src/components/TodoController.vue<template> <footer class="footer" v-show="todos.length" v-cloak> <button class="clear-completed" v-show="todos.length > remaining" @click="removeCompleted"> Clear completed </button> </footer> </template> <script> export default { methods: { removeCompleted() { this.$store.commit('removeCompleted'); } } }; </script>
src/store.jsexport default new Vuex.Store({ mutations: { removeCompleted(state) { state.todos = filters.active(state.todos); } } });
これで、ボタンクリックにより、リストデータから処理済み項目がすべて除かれます(図001)。モジュールsrc/store.js
は、これ以上書き替えしません。全体の記述は、以下のコード001にまとめたとおりです。
図001■ボタンで処理済み項目をすべて除く
コード001■チェック済み項目をデータから除く
src/store.js
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
const STORAGE_KEY = 'todos-vuejs-2.6';
const todoStorage = {
fetch() {
const todos = JSON.parse(localStorage.getItem(STORAGE_KEY) || '[]');
todos.forEach(function(todo, index) {
todo.id = index;
});
todoStorage.uid = todos.length;
return todos;
},
save(todos) {
localStorage.setItem(STORAGE_KEY, JSON.stringify(todos));
}
};
const filters = {
all(todos) {
return todos;
},
active(todos) {
return todos.filter((todo) =>
!todo.completed
);
},
completed(todos) {
return todos.filter((todo) =>
todo.completed
);
}
};
export default new Vuex.Store({
state: {
todos: todoStorage.fetch(),
visibility: 'all'
},
getters: {
filteredTodos: (state) =>
filters[state.visibility](state.todos),
remaining: (state) => {
const todos = state.todos.filter((todo) => !todo.completed);
return todos.length;
},
filters: (state) => filters,
allDone: (state, getters) => getters.remaining === 0
},
mutations: {
addTodo(state, todoTitle) {
const newTodo = todoTitle && todoTitle.trim();
if (!newTodo) {
return;
}
state.todos.push({
id: todoStorage.uid++,
title: newTodo,
completed: false
});
},
removeTodo(state, todo) {
state.todos = state.todos.filter((item) => item !== todo);
},
done(state, {todo, completed}) {
state.todos = state.todos.map((item) => {
if(item === todo) {
item.completed = completed
}
return item;
});
},
save(state) {
todoStorage.save(state.todos);
},
hashChange(state) {
const visibility = window.location.hash.replace(/#\/?/, '');
if (filters[visibility]) {
state.visibility = visibility;
}
},
setAllDone(state, value) {
state.todos.forEach((todo) =>
todo.completed = value
);
},
removeCompleted(state) {
state.todos = filters.active(state.todos);
}
}
});
02 ミューテーションへのコミットをまとめるヘルパー関数mapMutations()
Storeのmutations
に送るcommit()
をコンポーネントのmethods
オプションに定めるヘルパー関数がmapMutations()
です。commit()
メソッドをコンポーネントの$store
から参照しなくて済むようになります(「コンポーネント内におけるミューテーションのコミット」参照)。
コンポーネントsrc/components/TodoController.vue
でmethods
に加わるメソッドはひとつ(removeCompleted()
)で、mutations
に定められた同名のメソッドに引数もなくcommit()
を送っているだけです。この場合は、以下のようなmapMutations()
の簡易な構文が使えます。
関数の引数はオブジェクトで、プロパティがメソッドとして扱われ、値はミューテーションにコミットする文字列のメソッド名です。返されるオブジェクトが、コンポーネントのmethods
オプションに渡すオブジェクトになります。コンポーネントのメソッドはひとつなので、スプレッド構文...
による展開はしません(「Vue.js + Vuex入門 05」03「mapState()ヘルパー関数を使う」参照)。
src/components/TodoController.vueimport {mapState, mapGetters, mapMutations} from 'vuex'; export default { methods: /* { removeCompleted() { this.$store.commit('removeCompleted'); } } */ mapMutations({ removeCompleted: 'removeCompleted' }) }
コンポーネントsrc/components/TodoController.vue
のmethods
の定めを、mapMutations()
で書き替えました。メソッドがひとつなので、あまりありがたみが感じられないかもしれません。けれど、数が増えてきたとき、ヘルパー関数を使うことですっきりとまとめられるでしょう。コンポーネントの記述全体は、つぎのコード002のとおりです。
コード002■フッタのコンポーネントにヘルパー関数mapMutations()を使う
src/components/TodoController.vue
<template>
<footer class="footer" v-show="todos.length" v-cloak>
<span class="todo-count">
<strong>{{remaining}}</strong> {{remaining | pluralize}} left
</span>
<ul class="filters">
<li v-for="(value, key) in filters" :key="key">
<a
:href="'#/' + key"
:class="{selected: visibility === key}"
>
{{ key[0].toUpperCase() + key.substr(1) }}
</a>
</li>
</ul>
<button class="clear-completed"
v-show="todos.length > remaining"
@click="removeCompleted">
Clear completed
</button>
</footer>
</template>
<script>
import {mapState, mapGetters, mapMutations} from 'vuex';
export default {
name: 'TodoController',
filters: {
pluralize(n) {
return n === 1 ? 'item' : 'items';
}
},
computed: {
...mapState([
'todos',
'visibility'
]),
...mapGetters([
'remaining',
'filters'
])
},
methods: mapMutations({
removeCompleted: 'removeCompleted'
})
};
</script>
03 mapMutations()ヘルパー関数の標準構文
コンポーネントsrc/components/TodoItem.vue
のmethods
に定められたメソッドは、ミューテーションに送るコミットに、引数を添えなければなりません。このような場合は、mapMutations()
の標準的な構文を用いるのが原則です。引数のオブジェクトには、メソッドを収めます。この引数に渡されるのがcommit()
メソッドです。したがって、methods
オプションの定めは、つぎのように書き替えられます。いちいち$store
を参照しなくて済む分、少しすっきりしました。
src/components/TodoItem.vueimport { mapMutations } from 'vuex'; export default { methods: /* { removeTodo() { this.$store.commit('removeTodo', this.todo); }, onInput() { this.$store.commit('done', { todo: this.todo, completed: !this.todo.completed }); } } */ mapMutations({ removeTodo(commit) { commit('removeTodo', this.todo); }, onInput(commit) { commit('done', { todo: this.todo, completed: !this.todo.completed }); } }) }
04 mapMutations()ヘルパー関数の簡易構文に書き替えられる場合
前掲リスト項目のコンポーネントsrc/components/TodoItem.vue
の場合は、実はmapMutations()
ヘルパー関数の簡易構文に書き替えることもできます。引数をテンプレートのv-on
(@
)ディレクティブから渡すことができるからです。こちらの方が、よりすっきりするかもしれません。
src/components/TodoItem.vue<template> <div class="view"> <input @input="onInput({todo: todo, completed: !todo.completed})" > <!-- @input="onInput" --> <button @click="removeTodo(todo)"> <!-- @click="removeTodo"> --> </button> </div> </template> <script> export default { methods: mapMutations({ /* removeTodo(commit) { commit('removeTodo', this.todo); }, onInput(commit) { commit('done', { todo: this.todo, completed: !this.todo.completed }); } */ removeTodo: 'removeTodo', onInput: 'done' }) }; </script>
リスト項目のコンポーネントsrc/components/TodoItem.vue
のmethods
にはmapMutations()
の簡易構文を用いて、記述をつぎのコード003にまとめました。
コード003■リスト項目のコンポーネントにヘルパー関数mapMutations()を使う
src/components/TodoItem.vue
<template>
<div class="view">
<input
type="checkbox" class="toggle"
:value="todo.completed"
:checked="todo.completed"
@input="onInput({todo: todo, completed: !todo.completed})"
>
<label>{{todo.title}}</label>
<button
class="destroy"
@click="removeTodo(todo)">
</button>
</div>
</template>
<script>
import { mapMutations } from 'vuex';
export default {
name: 'TodoItem',
props: {
todo: Object
},
methods: mapMutations({
removeTodo: 'removeTodo',
onInput: 'done'
})
};
</script>
05 mapMutations()ヘルパー関数の標準構文を使わなければならない場合
項目入力のコンポーネントsrc/components/TodoInput.vue
にはmethods
にメソッドがひとつ(addTodo()
)定められ、同名のミューテーションにコミットと引数を送っています。ここでは、mapMutations()
の標準構文を使うしかありません。処理がcommit()
を呼び出すだけでけではないからです。
src/components/TodoInput.vue<script> import { mapMutations } from 'vuex'; export default { methods: /* { addTodo() { this.$store.commit('addTodo', this.newTodo); this.newTodo = ''; } } */ mapMutations({ addTodo(commit) { commit('addTodo', this.newTodo); this.newTodo = ''; } }) }; </script>
項目入力のコンポーネントsrc/components/TodoInput.vue
の記述はつぎのコード002のとおりです。これでモジュールの書き替えはすべて済みました。各モジュールのコードと動きは、CodeSandboxに公開した以下のサンプル001でお確かめください。
コード004■項目入力のコンポーネントにヘルパー関数mapMutations()を使う
src/components/TodoInput.vue
<template>
<input
v-model="newTodo"
class="new-todo" autofocus autocomplete="off"
placeholder="What needs to be done?"
@keypress.enter="addTodo"
>
</template>
<script>
import { mapMutations } from 'vuex';
export default {
name: 'TodoInput',
data() {
return {
newTodo: ''
};
},
methods: mapMutations({
addTodo(commit) {
commit('addTodo', this.newTodo);
this.newTodo = '';
}
})
};
</script>
サンプル001■vue-vuex-todo-mvc-06
Vue.js + Vuex入門
- Vue.js + Vuex入門 01: Storeを使う
- Vue.js + Vuex入門 02: クラスバインディングと項目の削除
- Vue.js + Vuex入門 03: データの変化に応じた処理とローカルへの保存
- Vue.js + Vuex入門 04: リスト表示する項目を選び出して切り替える
- Vue.js + Vuex入門 05: チェックをまとめてオン/オフする
- Vue.js + Vuex入門 06: チェックした項目をまとめて削除する
- Vue.js + Vuex入門 07: 項目のテキストをダブルクリックで再編集する
- Vue.js + Vuex入門 08: フォーカスをコントロールする
作成者: 野中文雄
作成日: 2019年10月26日
Copyright © 2001-2019 Fumio Nonaka. All rights reserved.