はじめに
「グローバルな状態管理はZustandやReduxで、永続化はlocalStorageを自前でラップして、複数タブ間の同期はBroadcastChannelを手書きして……」。ローカルファーストなアプリを作ろうとすると、こうして必要なライブラリがどんどん積み重なっていきます。しかもテーブル状のデータを扱いたくなった瞬間、状態管理ライブラリだけでは力不足になり、結局ミニDBのようなものを自作し始めた、という経験がある方も多いのではないでしょうか。
TinyBaseは、この「状態管理・永続化・同期・簡易DB」をひとつの小さなパッケージにまとめてくれるライブラリです。今回はその特徴と使い方を、実際に動かせるコード例とともに紹介します。
TinyBaseとは
TinyBaseは、ローカルファーストなJavaScript/TypeScriptアプリのための、リアクティブなインメモリデータストアです。公式サイトのキャッチコピーは「Local first. Sync on demand. Fast always.」で、オフラインでも即座に動作し、必要なときだけ同期するという設計思想を持っています。単なるKey-Valueストアにとどまらず、テーブル・行・セルという表形式のデータモデルや、SQLに近い感覚でクエリを書けるTinyQLも備えており、まさに「ブラウザに持ち込む小さなデータベース」と呼べる存在です。
主な特徴
- 圧倒的な軽量さ - 最小構成でgzip後7.2kB、フル機能でも15.6kB。依存関係はゼロです
- リアクティブ設計 - テーブル・行・セル単位でリスナーを登録でき、変更があった部分だけを効率よく再描画できます
- React/Solid/Svelteとの連携 -
useCellやuseTableのようなフックが用意されており、UIとデータを簡単に結び付けられます - TinyQLによるクエリ機能 - テーブル同士のJOINやフィルタ、集計をSQLライクな記法で表現できます
- CRDT対応の同期と永続化 -
MergeableStoreを使えばWebSocketやBroadcastChannel経由でデバイス間を同期でき、IndexedDBやSQLite、PostgreSQLなどへの永続化にも対応しています
インストール
npm install tinybase
yarn add tinybase
pnpm add tinybase
Reactなどのフレームワーク向けバインディングも同じパッケージに含まれており、tinybase/ui-reactのようにサブパスからインポートするだけで使えます。追加のパッケージインストールは不要です。
基本的な使い方
TinyBaseの基本はcreateStoreでストアを作り、setTableやsetCellでデータを操作するだけです。ここでは、ペットショップの在庫を管理しながら、変更をリアルタイムに検知する様子を見てみましょう。
ボタンを押すとfidoのsoldセルだけが更新され、リスナーが即座に反応して画面が最新の状態に書き換わります。ReduxのようなReducerやActionを用意しなくても、「どこを見て、変わったら何をするか」を宣言するだけでリアクティブなデータ操作が実現できるのがTinyBaseの気持ちよさです。
実践的なユースケース
Reactフックでコンポーネントに直結する
Reactアプリでは、tinybase/ui-reactのuseCellやuseTableフックを使うことで、コンポーネント側は「どのデータを表示したいか」を書くだけで済みます。ストアの変更を検知して再レンダーする処理はすべてTinyBaseが面倒を見てくれます。
「値上げ」ボタンを押すと、そのセルを購読している行だけが再レンダーされます。ストアはコンポーネントの外に存在するため、状態管理ライブラリとデータストアを別々に用意する必要がなくなります。
TinyQLで複数テーブルを結合・集計する
テーブルが増えてくると、「飼い主の州ごとに、もっとも平均価格が高いペットの種類は?」のような集計が欲しくなります。TinyQLを使えば、SQLのJOINやGROUP BYに近い感覚でこうしたクエリをリアクティブに定義できます。
petsテーブルとownersテーブルをownerIdで結合し、州・種類ごとの平均価格を降順で取得しています。元データが変われば結果も自動で再計算されるため、フィルタや集計のたびに手動で再クエリを書く必要がありません。
チェックポイントでUndo/Redo機能を作る
フォームやドローツールなど、ユーザーの操作を後から取り消したい場面は多くあります。TinyBaseのCheckpointsを使えば、ストアの状態にスナップショットを打ち、前後に移動するだけでUndo/Redoが実装できます。
「売却する」を押すたびにチェックポイントが積まれ、「元に戻す」を押すとgoBackward()で1つ前の状態に巻き戻ります。Undoスタックを自前で実装する手間がまるごと不要になるのは、地味ながら大きなメリットです。
まとめ
TinyBaseは、状態管理・表形式データの操作・クエリ・永続化・デバイス間同期という、ローカルファーストなアプリに必要な要素を、依存関係ゼロの小さなパッケージで一気に引き受けてくれるライブラリです。今回紹介したReactフックによるUI連携、TinyQLによる集計、Checkpointsを使ったUndo機能はそのごく一部にすぎず、IndexedDBやSQLiteへの永続化、CRDTによるリアルタイム同期など、さらに踏み込んだ機能も揃っています。「状態管理はこれ、永続化はこれ」とライブラリを積み上げる前に、一度TinyBase単体でどこまでできるか試してみる価値は十分にあるはずです。