0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Vue3入門:TODOアプリ作成完全ガイド

0
Last updated at Posted at 2026-04-23

🎯 この記事のゴール

  • Vue3でTODOアプリをゼロから作れる
  • 作るだけでなく「なぜそうするか」を理解する
  • 実務でも通用する書き方を身につける

🧠 完成イメージ

  • TODO追加
  • 完了チェック
  • 削除
  • 一覧表示

👉 シンプルだけどVueの基礎が全部詰まっています


🚀 Step0:環境構築

npm create vite@latest todo-app
cd todo-app
npm install
npm run dev

🧩 Step1:状態(データ)を定義

<script setup>
import { ref } from 'vue'

const todos = ref([])
const newTodo = ref('')
</script>

👉 ポイント

  • todos → リスト
  • newTodo → 入力値

✍️ Step2:TODO追加機能

<script setup>
const addTodo = () => {
  if (!newTodo.value) return

  todos.value.push({
    id: Date.now(),
    text: newTodo.value,
    done: false
  })

  newTodo.value = ''
}
</script>

🧠 注意点①:空入力を防ぐ

👉 実務では必須


🖥 Step3:テンプレート作成

<template>
  <input v-model="newTodo" placeholder="TODOを入力" />
  <button @click="addTodo">追加</button>

  <ul>
    <li v-for="todo in todos" :key="todo.id">
      {{ todo.text }}
    </li>
  </ul>
</template>

🧠 注意点②:必ずkeyをつける

👉 DOM更新のバグ防止


✅ Step4:完了機能

const toggleTodo = (id) => {
  const todo = todos.value.find(t => t.id === id)
  if (todo) todo.done = !todo.done
}
<li v-for="todo in todos" :key="todo.id">
  <input type="checkbox" @change="toggleTodo(todo.id)" />
  <span :style="{ textDecoration: todo.done ? 'line-through' : 'none' }">
    {{ todo.text }}
  </span>
</li>

🧠 注意点③:状態を直接変更する

👉 VueはリアクティブなのでOK


🗑 Step5:削除機能

const deleteTodo = (id) => {
  todos.value = todos.value.filter(t => t.id !== id)
}
<button @click="deleteTodo(todo.id)">削除</button>

🧠 注意点④:配列操作は再代入

👉 filter後は再代入が基本


🎯 完成コード

<script setup>
import { ref } from 'vue'

const todos = ref([])
const newTodo = ref('')

const addTodo = () => {
  if (!newTodo.value) return

  todos.value.push({
    id: Date.now(),
    text: newTodo.value,
    done: false
  })

  newTodo.value = ''
}

const toggleTodo = (id) => {
  const todo = todos.value.find(t => t.id === id)
  if (todo) todo.done = !todo.done
}

const deleteTodo = (id) => {
  todos.value = todos.value.filter(t => t.id !== id)
}
</script>

<template>
  <input v-model="newTodo" placeholder="TODOを入力" />
  <button @click="addTodo">追加</button>

  <ul>
    <li v-for="todo in todos" :key="todo.id">
      <input type="checkbox" @change="toggleTodo(todo.id)" />
      <span :style="{ textDecoration: todo.done ? 'line-through' : 'none' }">
        {{ todo.text }}
      </span>
      <button @click="deleteTodo(todo.id)">削除</button>
    </li>
  </ul>
</template>

🧠 実務で差がつく注意点

① IDの設計

❌ Date.now()だけ
👉 衝突の可能性あり

✅ UUIDなどを検討


② 状態の責務

👉 今回は1ファイルだが実務では分割

  • ロジック
  • UI

③ バリデーション

  • 空入力
  • 長さ制限

👉 UIだけでなくロジックでもチェック


④ パフォーマンス

  • リストが増えた場合
  • 再描画の影響

👉 keyが重要


⑤ 永続化(次のステップ)

👉 リロードで消える問題

対策:

  • localStorage
  • API保存

🚀 レベルアップ課題

ここまでできたら👇

  • フィルタ(未完了 / 完了)
  • 並び替え
  • 編集機能
  • 保存機能

🎯 よくある失敗

  • refを忘れる
  • keyをつけない
  • 状態とUIが混ざる
  • 直接DOM操作する

🔥 一番重要なポイント

👉 「状態(データ)を中心に考える」


🔚 まとめ

Vue3でTODOを作ると👇が身につく

  • 状態管理(ref)
  • イベント処理
  • リスト操作
  • UI更新
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?