JavaScriptのきほん「ToDoリストを作ろう(3)データを保存しよう」

スポンサーリンク
JavaScript

前回までで、ToDoの追加・完了チェック・削除ができるところまで作ってきた。
ただし、このままではページを再読み込みするたびにリストの内容が消えてしまう。
今回はlocalStorageを使ってブラウザにデータを保存し、再読み込みしてもリストが消えないようにする。あわせて、シリーズの最後として全体のコードを整理しておこう。

1. localStorageとは

localStorageは、ブラウザ上にデータを保存しておくための仕組みである。一度保存した内容は、ページを閉じたり再読み込みしたりしても消えることがなく、同じサイトを開いたときに読み出すことができる。ただし、保存できるのは文字列のみという制約がある。

主に使うメソッドは次の2つである。

  • localStorage.setItem(キー, 値):データを保存する
  • localStorage.getItem(キー):データを取り出す

配列やオブジェクトをそのまま保存することはできないため、JSON.stringify()で文字列に変換してから保存し、取り出すときはJSON.parse()で元の形に戻すという手順を踏む。

2. script.js(完成版)

前回のコードに、保存用の関数と読み込み処理を追加した完成版が以下である。
script.jsの中身をこの内容にまるごと置き換えてほしい。

// フォームとリストの要素を取得する
const form = document.getElementById('todo-form');
const input = document.getElementById('todo-input');
const list = document.getElementById('todo-list');

// localStorageに保存する際のキー名
const STORAGE_KEY = 'my-todo-list';

// 保存されているデータがあれば読み込み、なければ空配列にする
const savedData = localStorage.getItem(STORAGE_KEY);
const todos = savedData ? JSON.parse(savedData) : [];

// todosの内容をlocalStorageに保存する関数
function saveTodos() {
  localStorage.setItem(STORAGE_KEY, JSON.stringify(todos));
}

// リストを画面に描画する関数
function renderTodos() {
  list.innerHTML = '';

  todos.forEach((todo, index) => {
    const li = document.createElement('li');

    li.innerHTML = `
      <input type="checkbox" ${todo.done ? 'checked' : ''}>
      <span class="${todo.done ? 'completed' : ''}">${todo.text}</span>
      <button>削除</button>
    `;

    const checkbox = li.querySelector('input');
    checkbox.addEventListener('change', () => {
      todo.done = checkbox.checked;
      saveTodos();
      renderTodos();
    });

    const deleteButton = li.querySelector('button');
    deleteButton.addEventListener('click', () => {
      todos.splice(index, 1);
      saveTodos();
      renderTodos();
    });

    list.appendChild(li);
  });
}

// フォームが送信されたときの処理
form.addEventListener('submit', (event) => {
  event.preventDefault();

  const text = input.value.trim();
  if (text === '') {
    return;
  }

  todos.push({ text: text, done: false });

  input.value = '';
  saveTodos();
  renderTodos();
});

// ページを開いたときに、保存されているデータを表示する
renderTodos();

3. コードの解説

まず、ページが読み込まれた時点でlocalStorage.getItem(STORAGE_KEY)を呼び出し、保存済みのデータがあるかどうかを確認している。保存されていればJSON.parse()で配列に戻し、まだ何も保存されていなければ空配列[]を使うようにしている。三項演算子savedData ? JSON.parse(savedData) : []を使うことで、この分岐を1行で書いている。

saveTodos()は、現在のtodos配列をJSON.stringify()で文字列に変換し、localStorage.setItem()で保存するだけの、シンプルな関数である。この関数を、タスクを「追加」「完了チェック」「削除」したタイミング、つまりtodos配列の中身が変化するたびに呼び出すようにしている。
データが変わったら必ず保存する、という流れを徹底することで、常に最新の状態がブラウザに保存されることになる。

最後のrenderTodos()の呼び出しにも注目してほしい。これはイベントリスナーの中ではなく、ファイルの一番下、つまりページが読み込まれた直後に一度だけ実行される処理である。
これにより、localStorageから読み込んだ保存済みのデータが、ページを開いた瞬間にリストとして表示されるようになる。

4. 入力チェックの補足

前回までのコードにも、入力欄が空欄のままでは追加できないようにするif (text === '') { return; }という処理を入れていた。
今回のように保存機能を追加すると、空のタスクがうっかり保存され続けてしまうことも防げるため、この一行が地味に役立っていることがわかる。
余裕があれば、たとえば同じ文字列のタスクを二重に追加できないようにする、といったチェックを自分で追加してみるのもよい練習になるだろう。

5. 動作確認とシリーズのまとめ

タスクをいくつか追加し、チェックを入れたり削除したりしたあとで、ブラウザのページを再読み込みしてみよう。追加したタスクと、その完了状態がそのまま保持されていれば成功である。

3回にわたって、フォームからのデータ取得、DOM操作によるリストの描画、そしてlocalStorageによるデータの永続化という流れでToDoリストアプリを作ってきた。

個別の機能としては「イベントリスナー」「DOM要素の操作」「テンプレートリテラル」といったこれまでの記事で紹介してきた技術ばかりだが、それらを組み合わせることで、実際に使える小さなアプリケーションになることを体感できたのではないだろうか。

次のステップとしては、タスクの編集機能を追加したり、複数のリストを切り替えられるようにしたりと、いろいろな拡張が考えられる。ぜひ自分なりに手を加えてみてほしい。

コメント

タイトルとURLをコピーしました