この記事は 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のチュートリアルを改変したものを利用します。
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に少しでも興味をもつきっかけになれば幸いです。最後まで読んでくださり、ありがとうございました。