LoginSignup
10
2

More than 1 year has passed since last update.

【React×Dexie】LiveQueryを利用した、リアクティブなIndexedDB

Last updated at Posted at 2021-12-16

この記事は N・S高等学校 Advent Calendar 2021 の16日目です。

はじめに

本日、12月16日の記事は私、N高横浜キャンパス5期生の渡邊智晴(Slack: @とも)が担当させていただきます。予定では、今年の成果的なのを書く予定だったのですが、諸事情がありボツになっていまいました。そのため予定を変えて、私が今イチオシしているライブラリをご紹介したいと思います。

React×Dexie

みなさんは、Reactのグローバルな状態管理をどうされていますか。hooksのcontextで頑張る方法もあれば、reduxやrecoilなどのライブラリを利用する方法もあります。その中で、DexieのLiveQueryを利用するという新たな選択肢が出てきました。

Dexie

そもそもDexieとは、IndexedDBをラップしたライブラリです。これを使うことで、Webフロントで非同期なRDB的なものを作成することができます。TypeScriptにもバッチリ対応しており、補完などを含めた使い勝手も上々です。

LiveQuery

そして、Dexie v3.2.0 でLiveQueryという機能が追加されました!
これを使うことで、DBへの参照をリアクティブにすることができます!

DBを定義してみる

ここでは、Dexieのチュートリアルを改変したものを利用します。

db.ts
import Dexie, { Table } from 'dexie'

export interface Friend {
  id?: number
  name: string
  age: number
}

export class MySubClassedDexie extends Dexie {
  // テーブルの型を定義
  friends!: Table<Friend>

  constructor() {
    // IndexDBでの名前を設定
    super('myDatabase')

    // DBの初期化
    this.version(1).stores({
      friends: '++id, name, age'
    })
  }
}

export const db = new MySubClassedDexie()

解説

typescriptでDexieを利用するには、classを継承してDBを作成するのが一般的です。これによって、型を継承しつつTable周りの型を定義できるため、DBを利用する際もほぼ完璧に型が当てられます。しかし、継承は型を引き継ぐという意味合いが強く、DBとの接続・初期化などのロジックは、普通にconstructorの中で手続き的に行われています。

DBの内容を表示してみる

import { useLiveQuery } from "dexie-react-hooks"
import { db } from "./db"

// DBで定義したFriendsを、一覧表示するコンポーネント。年齢での範囲絞り込み可。
export function FriendList({ minAge, maxAge }: { minAge: number, maxAge: number }) {
  const friends = useLiveQuery(
    async () => {
      //
      // DBをクエリする
      //
      return db.friends
        .where('age')
        .between(minAge, maxAge)
        .toArray()
    },
    // クエリ時に依存する値
    [minAge, maxAge]
  )

  return (
    <ul>
      {friends?.map(friend => (
        <li key={friend.id}>
          {friend.name}, {friend.age}
        </li>
      ))}
    </ul>
  )
}

解説

DBの取得では、新たに追加されたuseLiveQueryを利用しています。使い方としては、第1引数はdbをクエリする関数を、第2引数ではuseEffectのような依存値が入ります。そして、返却値はuseStateの1つ目のような形で、リアクティブな値としてコンポーネント内で使えます。クエリ時のDBのアクセスは、O/Rマッパーのようにdb.[テーブル名].~という形で行えます。

DBを追加・更新・削除してみる

クエリ時と同じように、db.[テーブル名].~という形で行なっていきます。表示側でLiveQueryを利用している場合は表示更新を自動で行ってくれるため、本当に操作をするのみで問題ないです。ここでは、それぞれ簡単な例をご紹介します。

/*** 追加 ***/
const id = await db.friends.add(
  { name: "new user", age: 16 }
) // idを自動設定する際は、返却値がidとなる。

/*** 更新 ***/
await db.friends.update(id, { age: 17 })

/*** 削除 ***/
await db.friends.delete(id)

おわりに

React×Dexieによるグローバルな状態管理、いかがだったでしょうか。
LiveQueryがリリースされたことで、ReactとIndexedDBの連携が一気に現実的なものになりました。Dexieは使い勝手の良さからも、Reactのグローバルな状態管理の選択肢として、十分な機能を備えていると思います。
そして、Dexieにはまだまだ沢山の機能があります。個人的には、特にDexieのオンライン同期機能に注目をしています。こちらの記事は、また後日Qiitaに投稿する予定ですので、しばしお待ちください。
この記事が、Dexieに少しでも興味をもつきっかけになれば幸いです。最後まで読んでくださり、ありがとうございました。

10
2
0

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