localStorageを使って登録した情報を保存する JavaScript初学者講座

JavaScript

以前リファクタリングまで行った追加できるリストですが、どこにもデータを保存していなかったため、ブラウザを閉じたりページを読み込み直すと初期状態に戻ってしまいました。

以前の記事

このリストを簡易的なToDoリストとして使えるように、まずはブラウザに値を保存できるlocalStorageを使ってデータを残していきたいと思います。

localStorageとは

localStorageはブラウザでローカル環境に値を記録できる仕組みで、JavaScriptで読み書きが容易にできます。似たような機能でCookieがありますが、保持期限がなく削除されない限りは値が残ります。

永続的に値が残ってしまうので使用するときは削除できる仕組みを組み込んでおくことも必要です。
またユーザーはlocalStorageに保存している認識はないので、意図しないところ重要な情報が保存されるのは避けるべきです。個人情報のような機密情報をこの中に保持するのはやめましょう。

localStorageの値はブラウザの検証ツールで確認することができます。Chromeに例を挙げますと、検証ツールを立ち上げ「アプリケーション(Application)」→「ストレージ(Storage)」→「ローカルストレージ(Local Storage)」から確認ができます。

キャプチャにもありますが、値には配列やオブジェクトを使用することもできます。こちらから該当のURLを右クリックで値を削除することもできます。開発時にはこちらでデータの動きを見て確認をしていきましょう。

localStorageの使い方

localStorageの基本的な使い方、読み書きと削除の方法を勉強していきましょう。サンプルのコードではtextのinputに入力した値を、ボタン押下時に書き込みや読み取り、削除をできるようにしました。

コードの実行サンプル

データの書き込み

localStorageの書き込みには、setItemメソッドにkeyと値をセットにして渡します。

localStorage.setItem('key名' , '書き込む値');

実際に値を書き込むプログラムは下記のようになります。

localStorage.setItem('text', '新しいタスク');

データの読み込み

読み込みにはgetItemメソッドにkeyを渡します。

localStorage.getItem('key名');

localStorageのデータを読み込んでコンソールに表示するサンプルは下記の通りとなります。

const text = localStorage.getItem('text');
console.log(text)
// 新しいタスク

データの削除

データの削除はkeyを指定して削除するか、全て削除するかの2通りを勉強していきましょう。(全て削除といってもブラウザに保存されている全てのlocalStorageのデータではなく、表示しているURLのものみとなります。

// keyを指定して削除
localStorage.removeItem('key名');

// 全てのデータを削除
localStorage.clear();

localStorageを使ってToDoリストを作成

それではlocalStorageを使って以前に作ったリストのデータを保存できるようにしていきます。完成したコードは下記のようになりました。

コードの実行サンプル

<ul class="list"></ul>

<button class="button button--add">追加</button>

<script>

class ListCreate {

  constructor() {
      this.view();
      const listItem = document.querySelectorAll(".list__item");
      const state = JSON.parse(localStorage.getItem("todoList"));
      this.add();

        listItem.forEach((value, index) =>{
          const el = this.elements(value);
          this.delete(el, value);
          this.edit(el, value)
          this.submit(el, value);
        })

  }

  // リストの要素をオブジェクトに代入
  elements(listItem) {
      const element = {
        itemBody: listItem.querySelector(".list__itemBody"),
        itemDeleteButton: listItem.querySelector(".button--delete"),
        itemEditButton: listItem.querySelector(".button--edit"),
        itemSubmitButton: listItem.querySelector(".button--submit")
      }
      return element;
  }
  
  // 編集
  edit(el, listItem) {
    el.itemEditButton.addEventListener("click", () => {
      const inputForm = document.createElement("input");
      inputForm.type = "text";
      inputForm.className = "inputText";
      inputForm.value = el.itemBody.textContent;

      el.itemBody.replaceChildren(inputForm);
      
      el.itemDeleteButton.classList.add("hidden");
      el.itemEditButton.classList.add("hidden");
      el.itemSubmitButton.classList.remove("hidden");
    });
  }

  // 編集決定
  submit(el, listItem) {
    el.itemSubmitButton.addEventListener("click", () => {
      const inputForm = listItem.querySelector(".inputText");

      el.itemBody.replaceChildren(inputForm.value);

      el.itemDeleteButton.classList.remove("hidden");
      el.itemEditButton.classList.remove("hidden");
      el.itemSubmitButton.classList.add("hidden");

      this.update();
    });
  }

  // 削除
  delete(el, listItem, index) {
    el.itemDeleteButton.addEventListener("click", () => {
      listItem.remove();
      this.update();
    });
  }

  // 追加
  add() {
    const list = document.querySelector(".list");
    const itemAddButton = document.querySelector(".button--add");

    itemAddButton.addEventListener("click", () => {
      const listItem = document.createElement("li");
      listItem.className = "list__item";
      listItem.innerHTML = `
        <div class="list__itemBody">新規タスク</div>
        <div class="list__itemButtons">
          <div class="button button--delete">削除</div>
          <div class="button button--edit">編集</div>
          <div class="button button--submit hidden">決定</div>
        </div>
      `;

      const el = this.elements(listItem);
      this.delete(el, listItem);
      this.edit(el, listItem)
      this.submit(el, listItem);
      list.appendChild(listItem);

      this.update();

    })
  }

  // 表示
  view() {
    const list = document.querySelector(".list");
    const todoList = JSON.parse(localStorage.getItem("todoList"));
    if ( todoList ) {
      todoList.forEach(value => {
        const listItem = document.createElement("li");
        listItem.className = "list__item";
        listItem.innerHTML = `
          <div class="list__itemBody">${value.body}</div>
          <div class="list__itemButtons">
            <div class="button button--delete">削除</div>
            <div class="button button--edit">編集</div>
            <div class="button button--submit hidden">決定</div>
          </div>`;
        list.appendChild(listItem);
      });
    }
  }

  // 更新
  update() {
    const listItem = document.querySelectorAll(".list__item");
    let todoList = [];
    listItem.forEach((value, index) =>{
      let bodyData = value.querySelector(".list__itemBody");
      let data = {
        id: index,
        body: bodyData.textContent
      }
      todoList.push(data);
    });
    localStorage.removeItem("todoList");
    localStorage.setItem("todoList", JSON.stringify(todoList));
  }

}

new ListCreate();

前回と変わったところを説明していきます。

初期表示のためlocalStorageからデータを読み取りしてHTML生成

viewメソッドの部分になりますが、localStorageからデータを読み取り、配列の長さの分だけループしてHTMLを生成しています。
このメソッドはconstructorメソッドで初期化時に実行することでページアクセス時にlocalStorageのデータからリストを作成するようにしています。

localStorageのデータを更新

localStorageのデータを更新するメソッドがupdateになります。このToDoリストではlocalStorageにオブジェクトを含む配列のデータを記録していますが、localStorageにはオブジェクト内を検索して削除するような機能がありません。

今回は一度localStorage内のデータを削除し、HTML上のリストから新たにデータを作成してからlocalStorageへ再度書き込んでいます。

updateメソッドはdelete(削除)や、submit(編集の決定)、add(追加)のメソッドの最後に記述することで、リスト更新後の状態をlocalStorageに保存しています。

終わりに

localStorageを使うことによってようやく実用的なWEBアプリケーションになってきました。ただ、localStorageでは別のブラウザでデータを共有できなかったり、データの安全性には欠けるところがありますので、正式なサービスとして打ち出すためにはもっとたくさんの機能を実装する必要があるでしょう。

これからも引き続きこのToDoリストを進化させていくコードを考えていきますので、一緒に勉強してもらえると嬉しいです。

ここまで読んでくださり、ありがとうございました。

制作協力
サムネイル制作:うみ Twitter

コメント

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