IndexedDBはブラウザにデータを保持できる仕組みで、大量のデータをフロントで操作する場合や、APIのレスポンス等をキャッシュしたりする時に便利です。
ただ、IndexedDB APIをそのまま使うと同期処理の対応を自前でやらなければならなかったり(入れ子になるので可読性が悪くバグ発生率が上がりそう)、接続までの手順が長かったり(コード量が増える)します。
Dexie.jsがとても良かったので、試したコードをメモしておきます。

初期表示

取得ボタンクリック後

テストコード

今回はリロードで初期化や、遷移・離脱でデータ残さないようにしたかったので、DB削除もしています。temporary storageが使えれば良かったのですが、FireFoxしか対応していないようでした。

% yarn add dexie
<template>
  <div>
    <v-btn @click="getData()">取得</v-btn>

    <h1>table1</h1>
    <div>key: {{ key }}</div>
    <div>hashValue: {{ hashValue }}</div>
    <div>arrayValue: {{ arrayValue }}</div>

    <h1>table2</h1>
    <div>{{ datas }}</div>
  </div>
</template>

<script>
import Dexie from 'dexie'

const DB_NAME = 'MyDatabase'

export default {
  // 今回は、遷移したらDBを削除する。即時ではなくCloseされた後なので、別タブで使っていてもOK
  beforeRouteLeave (_to, _from, next) {
    this.deleteIndexedDB()
    next()
  },

  data () {
    return {
      db: null,
      key: { text: 'a', option: false },
      hashValue: null,
      arrayValue: null,
      datas: null
    }
  },

  created () {
    this.db = new Dexie(DB_NAME)
    // テーブル定義みないなもの。versionでmigrationみたいな事ができる。実際に作られるのはaddやputした時
    this.db.version(1).stores({
      table1: 'key, hashValue, *arrayValue',
      table2: '++id, value'
    })

    // addでも良いけど、putにすると更新もできる
    this.db.table1.put({
      key: JSON.stringify(this.key), // ハッシュのままだとエラーになるので、JSONに変換
      hashValue: { a: 1, b: 2 },
      arrayValue: [1, 2]
    })
      .catch((_error) => {})

    // idが自動採番される -> id: 1
    this.db.table2.add({
      value: 'test'
    })
      .catch((_error) => {})
    // putしてもカウントアップされて追加される -> id: 2
    this.db.table2.put({
      value: 'test'
    })
      .catch((_error) => {})
    // id指定でput -> 更新される
    this.db.table2.put({
      id: 2,
      value: 'test2'
    })
      .catch((_error) => {})

    // 今回は、リロードや閉じたらDBを削除する
    addEventListener('beforeunload', this.deleteIndexedDB)
  },

  beforeDestroy () {
    // eslint-disable-next-line no-console
    console.log('beforeDestroy')

    // 後片付けはした方が良い
    removeEventListener('beforeunload', this.deleteIndexedDB)
    // 明示的にcloseしなくても問題ないけど
    this.db.close()
  },

  methods: {
    deleteIndexedDB () {
      // eslint-disable-next-line no-console
      console.log('deleteIndexedDB', DB_NAME)

      indexedDB.deleteDatabase(DB_NAME)
    },

    async getData () {
      let result = false
      // 同期で対象データ取得。存在しない場合の処理(APIリクエスト等)の時に入れ子にしなくても良くなる
      await this.db.table1.get(JSON.stringify(this.key))
        .then((item) => {
          this.hashValue = item.hashValue
          this.arrayValue = item.arrayValue
          result = true
        })
      .catch((_error) => {})

      if (!result) { return }

      // 全件取得してみる
      await this.db.table2.toArray()
        .then((items) => {
          this.datas = items
        })
      .catch((_error) => {})
    }
  }
}
</script>

表示中のIndexedDBの中身

遷移後にIndexedDBが削除される事を確認

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です