🔰 Vue3入門|TODOアプリで学ぶ「表示切り替え」と自動更新の仕組み
Vueの基本文法を一通り学んだあと、こんな壁にぶつかる人は多いです。
- ボタンを押したら表示が変わる仕組みがよく分からない
- DOMを触っていないのに、なぜ画面が更新されるのか不思議
computedが何をしているのか曖昧
この記事では、TODOアプリを題材にしながら
Vueがどのように「状態 → 表示」を自動でつないでいるのかを、できるだけ噛み砕いて解説します。

目次
🎯 この記事のゴール
この記事を読み終えたときに、次のことが理解できていればOKです。
- 「表示の切り替え」はDOM操作ではなく状態管理で行う
computedは「表示専用の自動計算結果」である- Vueは「データが変わったら画面を作り直す」仕組みを持っている
完成イメージ
- TODOを追加できる
- TODOをクリックすると完了/未完了を切り替えられる
- 「すべて / 未完了 / 完了」で表示を切り替えられる
使用するVueの書き方について
この記事では Vue3の最新スタイルを使います。
- Composition API
<script setup>ref/computed
全体の完成コード(Vue3)
template
<template>
<div class="todo-app">
<h2>TODOリスト</h2>
<!-- 追加エリア -->
<div>
<input v-model="text" placeholder="やることを入力" />
<button @click="addTodo">追加</button>
</div>
<!-- 表示切り替え -->
<div class="filters">
<button @click="filter = 'all'">すべて</button>
<button @click="filter = 'active'">未完了</button>
<button @click="filter = 'done'">完了</button>
</div>
<!-- TODO一覧 -->
<ul>
<li
v-for="(todo, index) in filteredTodos"
:key="index"
:class="{ done: todo.done }"
>
<span @click="toggleTodo(index)">
{{ todo.text }}
</span>
<button @click="removeTodo(index)">削除</button>
</li>
</ul>
</div>
</template>
script(Composition API)
<script setup>
import { ref, computed } from "vue";
// 入力欄
const text = ref("");
// TODOの元データ
const todos = ref([]);
// 表示モード
const filter = ref("all");
// 追加
const addTodo = () => {
if (!text.value) return;
todos.value.push({
text: text.value,
done: false
});
text.value = "";
};
// 削除
const removeTodo = (index) => {
todos.value.splice(index, 1);
};
// 完了 / 未完了切り替え
const toggleTodo = (index) => {
todos.value[index].done = !todos.value[index].done;
};
// 表示用の配列(自動計算)
const filteredTodos = computed(() => {
if (filter.value === "active") {
return todos.value.filter(todo => !todo.done);
}
if (filter.value === "done") {
return todos.value.filter(todo => todo.done);
}
return todos.value;
});
</script>
style(最低限)
<style>
.done {
text-decoration: line-through;
color: gray;
}
</style>
🧠 仕組みを順番に理解する
① 表示を切り替える正体は「状態」
const filter = ref("all");
この変数は、
- 今「どれを表示したいか」を記録するためのもの
- 画面を直接操作しているわけではない
ボタンを押すと、ただ filter の中身が変わるだけです。
<button @click="filter = 'active'">未完了</button>
② 表示用の配列を作る computed
const filteredTodos = computed(() => {
if (filter.value === "active") {
return todos.value.filter(todo => !todo.done);
}
if (filter.value === "done") {
return todos.value.filter(todo => todo.done);
}
return todos.value;
});
これは日本語にするとこうです。
「
filter と todos を見て
今表示すべき配列を返す
」
ポイント
- 自分で呼ばない
- 自分で更新しない
- 元データ(todos)は壊さない
👉 表示専用のコピー
③ 表示は v-for に任せる
<li v-for="(todo, index) in filteredTodos">
- 並べているのは
filteredTodos todosを直接操作していない
これが 状態と表示を分ける設計です。
④ DOM操作をしていないのに動く理由
このアプリでは、
document.querySelectortextContentclassList
を一切使っていません。
代わりにやっているのは、
- 状態(ref)を変更
- Vueが自動で再描画
👉 Vueは
「データが変わったら、画面を作り直す」
というルールで動いています。
🎯 ここまで理解できたらOK
次のことが説明できれば、Vueの基礎はしっかり身についています。
- 表示切り替えは DOM ではなく 状態で行っている
computedは「自動で作られる表示用データ」- template は「状態をどう見せるか」だけを書く
プログラミング備忘録


【Vue】リアクティブが壊れる原因7選|画面が更新されないNG例まとめ2025
Vueで値は変わっているのに画面が更新されない原因を解説。data未定義、DOM直接操作、computedの誤用など、リアクティブが壊れるNG例を初心者向けにまとめました。
プログラミング備忘録


TODOアプリを理解しながら作る|JavaScriptからVue3への橋渡し入門2026
Vueのチュートリアル後に「なぜ動くのか分からない」と感じていませんか?JavaScriptで作ったTODOアプリをVue3で作り直し、ref・リアクティブ・v-forの仕組みを理解しなが…
その他関連記事はこちら→プログラミング備忘録

コメント