MENU

Vue3 TODOアプリ入門|リロードしても消えない仕組みをlocalStorageで完全解説

Vue3 TODOアプリ入門|リロードしても消えない仕組みをlocalStorageで完全解説

localStorageについての解説画像
TOC

〜リロードしても消えない仕組みを理解する〜

VueでTODOアプリを作れるようになると、
次に必ずぶつかる壁があります。

「ページを更新すると全部消える問題」

これはバグではありません。
「保存していない」だけです。

この記事では、

  • なぜデータが消えるのか
  • ブラウザに保存するとはどういうことか
  • Vue3でどう実装するのか

超噛み砕いて解説します。


なぜTODOは消えるのか?

まず前提。

const todos = ref([]);

これは メモリ上のデータです。

  • ページを閉じる
  • リロードする

👉 メモリはリセットされる

だから消える。


解決策:ブラウザに保存する

サーバーを使わなくても、
ブラウザ自身にデータを保存する仕組みがあります。

それが localStorage


localStorageとは?

一言で言うと

👉 ブラウザにある「小さな引き出し」

特徴:

  • ページを閉じても残る
  • サーバー不要
  • 文字列しか保存できない

超シンプルな例(生JavaScript)

localStorage.setItem("message", "こんにちは");
localStorage.getItem("message");
// → "こんにちは"

重要:そのままでは配列は保存できない

TODOは配列+オブジェクトです。

[
  { id: 1, text: "勉強する", done: false }
]

localStorageは
配列を直接保存できない

そこで使うのが JSON


JSONとは?

保存用の「文字列フォーマット」

JSON.stringify(配列やオブジェクト)
JSON.parse(文字列)

const data = [{ text: "勉強" }];

const string = JSON.stringify(data);
// "[{"text":"勉強"}]"

JSON.parse(string);
// 元の配列に戻る

Vue3での実装(全体像)

これからやることは3つだけ👇

  1. TODOが変わったら保存する
  2. 保存するときは JSON にする
  3. ページ表示時に復元する

script setup(ロジック部分)

<script setup>
import { ref, watch, onMounted } from "vue";

const text = ref("");
const todos = ref([]);

TODOを追加する

const addTodo = () => {
  if (!text.value.trim()) return;

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

  text.value = "";
};

ポイント

  • ref の中身は .value
  • 配列に push すると Vue が反応する
  • id は「そのTODO自身を識別するため」

削除する(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;
  }
};

ここが核心:watchで自動保存

watchとは?

👉 「値が変わった瞬間を監視する」機能


todos が変わったら保存する

watch(
  todos,
  (newTodos) => {
    localStorage.setItem(
      "todos",
      JSON.stringify(newTodos)
    );
  },
  { deep: true }
);

なぜ deep: true が必要?

todos の中身はこう👇

[
  { text: "勉強", done: false }
]
  • 配列の中に
  • オブジェクトがある

done が変わっただけでは
通常の watch では検知されない

👉 深い変更も見る = deep


ページ表示時に復元する

onMounted(() => {
  const saved = localStorage.getItem("todos");
  if (saved) {
    todos.value = JSON.parse(saved);
  }
});

onMountedとは?

👉 画面が表示された直後に一度だけ実行される

用途:

  • 初期データ取得
  • localStorage復元
  • API呼び出し

template(完成版)

<template>
  <div>
    <input v-model="text" />
    <button @click="addTodo">追加</button>

    <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>

何ができるようになったか?

この時点であなたは👇

  • Vueのリアクティブを理解
  • 状態が「どこにあるか」分かる
  • データを永続化できる

つまり、

「チュートリアル卒業」


よくある誤解

❌ localStorage = Vueの機能
ただのブラウザ機能

❌ watch = 難しい
「変わったらやる」だけ

関連記事紹介

その他関連記事はこちら→Programming Notes

Let's share this post !

Author of this article

初心者の私がコーディングをしていて躓いたところをピックアップして日々の備忘録として発信しています^^
楽しくコーディングを身に着けていけるように日々勉強中です★

Comments

To comment

TOC