Vue3 TODOアプリ実践|v-forでkeyにindexを使ってはいけない理由
〜「動く」から「壊れにくい」設計へ〜
VueでTODOアプリを作れるようになってきた頃、
多くの人が こんな書き方をしています。
<li v-for="(todo, index) in todos" :key="index">
学習としては正解です。
でも 実務ではこの書き方は避けます。
この記事では、
を 順を追って説明します。

TOC
なぜ key=”index” は危険なのか?
Vueは画面を更新するとき、
こう考えています。
「前と同じ要素か?それとも別物か?」
その判断材料が key です。
問題が起きる具体例
todos = [
"勉強する",
"買い物に行く",
"洗濯する"
];
表示されている状態:
0: 勉強する
1: 買い物に行く
2: 洗濯する
ここで 真ん中を削除すると…
[
"勉強する",
"洗濯する"
]
indexはこう変わります。
| 内容 | 前のindex | 削除後 |
|---|---|---|
| 勉強する | 0 | 0 |
| 洗濯する | 2 | 1 |
Vueはこう誤解することがあります👇
「あれ? index=1 は前もあったな…
中身が変わっただけか」
👉 別のTODOなのに、同じものとして扱われる
これが バグの温床になります。
解決策:TODOに「id」を持たせる
現場では 配列の順番ではなく、データ自体を識別します。
TODOの形を変える
{
id: 123456789,
text: "勉強する",
done: false
}
Vue3(Composition API)での実装
script(ロジック部分)
<script setup>
import { ref, computed } from "vue";
const text = ref("");
const todos = ref([]);
TODOを追加する
const addTodo = () => {
if (!text.value.trim()) return;
todos.value.push({
id: Date.now(), // 一意なID
text: text.value,
done: false
});
text.value = "";
};
なぜ Date.now()?
- 毎回ほぼ被らない数値
- 学習用途には十分
- 実務では UUID を使うこともある
削除処理(indexを使わない)
const removeTodo = (id) => {
todos.value = todos.value.filter(todo => todo.id !== id);
};
ポイント
filterは 新しい配列を作る- Vueは 変更を確実に検知できる
- index に依存しない
完了状態を切り替える
const toggleTodo = (id) => {
const todo = todos.value.find(todo => todo.id === id);
if (todo) {
todo.done = !todo.done;
}
};
残り件数を表示する(computed)
const remainingCount = computed(() => {
return todos.value.filter(todo => !todo.done).length;
});
なぜ computed?
- todos が変わったときだけ再計算
- 自動で最新の値になる
- 表示用ロジックに最適
template(完成版)
<template>
<div>
<input v-model="text" />
<button @click="addTodo">追加</button>
<p>残り {{ remainingCount }} 件</p>
<ul>
<li
v-for="todo in todos"
:key="todo.id"
>
<span
@click="toggleTodo(todo.id)"
:style="{ textDecoration: todo.done ? 'line-through' : 'none' }"
>
{{ todo.text }}
</span>
<button @click="removeTodo(todo.id)">削除</button>
</li>
</ul>
</div>
</template>
この実装で身につく考え方
| 初心者 | 今回 |
|---|---|
| indexで操作 | idで操作 |
| 表示順に依存 | データ基準 |
| 動けばOK | 壊れにくい |
Summary
keyは 見た目用ではなく識別子- index は変わるが、id は変わらない
- Vueでは 「データ設計」が重要
この考え方ができるようになると、
- コンポーネント分割
- localStorage 保存
- 実務案件
すべて一気に理解しやすくなります。
Programming Notes


【Vue3入門】TODOアプリで理解するcomputedと表示切り替え|DOM操作しない理由を解説
Vue3のcomputedがよく分からない初心者向けに、TODOアプリを使って「表示切り替え」と自動更新の仕組みを解説。DOM操作をしなくても画面が変わる理由がスッと理解できます…
Programming Notes


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

Comments