TODOアプリを「理解しながら」作る|JavaScriptからVueへの橋渡し
Vueのチュートリアルを一通り終えたあと、
「動くけど、なぜ動くのかわからない」
「コードは読めるのに、ゼロから書けない」
そんなモヤモヤを感じていませんか?
この記事では、JavaScriptで作ったTODOアプリをVue3で作り直しながら、
Vueの一番大事な考え方である「状態(state)」と「リアクティブ」の正体を、
コードを分解しながら丁寧に解説します。
完成を目指すだけでなく、
「なぜこの書き方になるのか」を理解できることがゴールです。

🎯 あなたのゴール
この記事を読み終えたときに、次の状態になることが目標です。
refと.valueの意味が説明できる- なぜ配列の中身が変わると画面が更新されるのか分かる
indexの正体が分かる- VueがDOM操作を肩代わりしてくれている感覚がつかめる
完成イメージ:Vue版TODOアプリ
- テキストを入力して「追加」
- TODOをクリックすると完了 / 未完了が切り替わる
- 削除ボタンでその行だけ消える
<template>
<div>
<input v-model="text" />
<button @click="addTodo">追加</button>
<ul>
<li
v-for="(todo, index) in todos"
:key="index"
:class="{ done: todo.done }"
>
<span @click="toggleTodo(index)">
{{ todo.text }}
</span>
<button @click="removeTodo(index)">削除</button>
</li>
</ul>
</div>
</template>
<script setup>
import { ref } from "vue";
const text = ref("");
const todos = ref([]);
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;
};
</script>
<style>
.done {
text-decoration: line-through;
color: gray;
}
</style>
🧠 Vueで一番大事な考え方:「状態(state)」
まず最初に理解してほしいのがこれです。
JavaScriptだけの場合
const todos = [];
これはただの配列です。
Vueの場合
const todos = ref([]);
これは「Vueに監視されている状態」です。
実は中身はこうなっています。
todos = {
value: []
}
Vueは
👉 value の中身が変わった瞬間を検知して
👉 画面を自動で更新します
なぜ .value が必要なのか?
Vueの ref は「箱」です。
- 箱そのもの →
todos - 中身 →
todos.value
だから追加するときはこう書きます。
todos.value.push("買い物");
もし .value を忘れると
👉 Vueは「変化が起きた」と認識できません。
🧩 TODOは「文字」ではなく「オブジェクト」で持つ
最初はこう書きたくなります。
todos.value.push("買い物");
でもこれだと、後で困ります。
- 完了したか?
- チェック済みか?
- 日付は?
👉 情報を追加できない
正解はこちら
todos.value.push({
text: "買い物",
done: false
});
これで、
text:表示する文字done:完了状態
という状態を持つTODOになります。
これは実務でも必須の考え方です。
✏️ addTodo を1行ずつ解説
const addTodo = () => {
「追加ボタンを押したときに実行される関数」
if (!text.value) return;
意味は👇
- 入力欄が空なら
- 何もせず終了
省略しないとこうです。
if (text.value === "") {
return;
}
todos.value.push({
text: text.value,
done: false
});
- todos配列に
- 新しいTODOオブジェクトを追加
text.value = "";
入力欄を空に戻して、使いやすくしています。
🔁 v-for の index の正体
<li v-for="(todo, index) in todos">
これはJavaScriptでいうとこうです。
todos.forEach((todo, index) => {
// todo → 中身
// index → 番号
});
例:
| index | todo |
|---|---|
| 0 | { text: “買い物”, done: false } |
| 1 | { text: “掃除”, done: true } |
🗑 削除処理で使っている index
const removeTodo = (index) => {
todos.value.splice(index, 1);
};
splice の意味
splice(消す位置, 消す個数)
例:
["A", "B", "C"].splice(1, 1);
// → ["A", "C"]
👉 押した行だけ消える理由はこれです。
✅ 完了状態の切り替え(トグル)
todos.value[index].done = !todos.value[index].done;
これはON / OFFの切り替え。(スイッチみたいな感覚)
分解するとこうです。
if (todos.value[index].done === true) {
todos.value[index].done = false;
} else {
todos.value[index].done = true;
}
🎨 class の切り替えはVueがやってくれる
:class="{ done: todo.done }"
これは裏側では、こんなことをしています。
if (todo.done) {
li.classList.add("done");
} else {
li.classList.remove("done");
}
👉 DOM操作をVueが代行してくれている。
まとめ
ここまで理解できると、
- JavaScriptの配列・オブジェクトを理解している。
- Vueのリアクティブの正体がわかる。
- indexを使った操作ができるようになる。
- 「なぜこのコードなのか」を説明できるようになる。
引き続きVueの理解を一緒に深めていきましょう!!^^


その他関連記事はこちら→プログラミング備忘録

コメント