3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

IndexedDBを活用したページ状態の保存、復元、削除

Last updated at Posted at 2023-08-06

Webアプリケーションにおいて、ユーザーのアクションや設定に基づきページの状態を保存、復元、または削除することは頻繁に求められる要件となっています。この記事では、そのようなタスクをIndexedDBを利用して実現する方法と、実装時の注意点について解説します。

1. IndexedDBとは?

IndexedDBは、ブラウザ内での大量データの保存を目的とした低レベルAPIです。これはオブジェクトベースのデータベースで、オブジェクトを直接保存することが可能です。

2. ページ状態の保存、復元、削除

以下のコードは、ページのURLをキーとしてデータを保存、読み込み、または削除する手法を示しています。

Javascript:

script.js
const PageState = {
  db: null,
  init() {
    const request = indexedDB.open("myDatabase", 1);
    request.onupgradeneeded = (event) => {
      this.db = event.target.result;
      const objectStore = this.db.createObjectStore("pageState", {
        keyPath: "url",
      });
    };
    request.onsuccess = (event) => {
      this.db = event.target.result;
    };
  },
  saveState(data) {
    const transaction = this.db.transaction(["pageState"], "readwrite");
    const objectStore = transaction.objectStore("pageState");
    objectStore.put({ url: window.location.href, data });
  },
  loadState() {
    const transaction = this.db.transaction(["pageState"]);
    const objectStore = transaction.objectStore("pageState");
    const request = objectStore.get(window.location.href);
    return new Promise((resolve, reject) => {
      request.onsuccess = (event) => {
        resolve(request.result ? request.result.data : null);
      };
      request.onerror = (event) => {
        reject(new Error("Data retrieval failed"));
      };
    });
  },
  deleteState() {
    const transaction = this.db.transaction(["pageState"], "readwrite");
    const objectStore = transaction.objectStore("pageState");
    const request = objectStore.delete(window.location.href);
    return new Promise((resolve, reject) => {
      request.onsuccess = (event) => {
        resolve(true);
      };
      request.onerror = (event) => {
        reject(new Error("Data deletion failed"));
      };
    });
  },
};

// 初期化
PageState.init();


HTML:

index.html
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>IndexedDB Sample with URL as Key</title>
</head>

<body>
    <div>
        <input type="text" id="dataInput" placeholder="Enter some data">
        <!-- PageStateオブジェクトを通じて関数を呼び出す -->
        <button onclick="PageState.saveState(document.getElementById('dataInput').value)">Save</button>
        <button onclick="retrieveData()">Load</button>
        <!-- 以下が追加されたdeleteStateメソッドを呼び出すボタンです -->
        <button onclick="deleteData()">Delete</button>
    </div>
    <div id="output"></div>
    <script src="script.js"></script>
    <script>
        // loadStateの返り値を使用してデータを取得
        async function retrieveData() {
            try {
                const data = await PageState.loadState();
                document.getElementById('output').innerText = data || "No data found";
            } catch (error) {
                console.error("Error retrieving data:", error);
            }
        }

        // 以下が追加されたdeleteStateメソッドを呼び出す関数です
        async function deleteData() {
            try {
                await PageState.deleteState();
                document.getElementById('output').innerText = "Data deleted successfully";
            } catch (error) {
                console.error("Error deleting data:", error);
            }
        }
    </script>
</body>

</html>

3. データの保持期間の追加

Webアプリケーションでは、データの保持期間を設定することが求められる場面があります。IndexedDBを使用して、データの保存時に現在の日時を保存し、その日時を基にしてデータの有効期限を判定することができます。

データの保存時に現在の日時を追加:

データを保存する際に、現在の日時も一緒に保存します。

saveState(data) {
    const transaction = this.db.transaction(["pageState"], "readwrite");
    const objectStore = transaction.objectStore("pageState");
    const now = new Date().getTime(); // 現在の日時を取得
    objectStore.put({ url: window.location.href, data, timestamp: now });
}

データの読み込み時に日時を確認して古いデータを削除:

データを読み込む際に、保存された日時を確認し、指定した期間を超えている場合はそのデータを削除します。

loadState() {
    const transaction = this.db.transaction(["pageState"]);
    const objectStore = transaction.objectStore("pageState");
    const request = objectStore.get(window.location.href);
    return new Promise((resolve, reject) => {
        request.onsuccess = (event) => {
            const now = new Date().getTime();
            const oneDay = 24 * 60 * 60 * 1000; // 24時間をミリ秒で表現
            if (request.result && (now - request.result.timestamp) <= oneDay) {
                resolve(request.result.data);
            } else {
                this.deleteState(); // 期間を超えているデータを削除
                resolve(null);
            }
        };
        request.onerror = (event) => {
            reject(new Error("Data retrieval failed"));
        };
    });
}

上記の変更を加えることで、データの保持期間を1日とし、それを超えたデータは自動的に削除されるようになります。必要に応じて保持期間を調整することができます。

4. 考慮すべき問題点

  • エラーハンドリング: データベースのオープンやデータの操作時のエラーハンドリングは欠かせません。
  • データベースのバージョン管理: バージョンが変わった際の適切な処理が必要です。
  • 容量制限: IndexedDBの容量制限を超えるとエラーが発生しますので、この制限を意識してください。
  • セキュリティ: 機密情報を保存する場合、データの暗号化などのセキュリティ対策が必要です。
  • ブラウザの互換性: すべてのブラウザでIndexedDBがサポートされているわけではないため、互換性を確認することが大切です。

5. まとめ

IndexedDBは、ブラウザ内でのデータの効率的な保存、復元、削除を実現する強力なツールです。しかし、その実装には上記のような多くの注意点が伴います。これらの要点をしっかりと把握しながら、ページの状態管理を適切に行うことが求められます。

6. 参考リンク

詳しいコード例や動作デモを確認したい方は、以下のGitHubリポジトリをご参照ください:

3
3
5

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?