🛠️
[React]DexieのuseLiveQueryをカスタムhookで使いたい
useLiveQueryとは
indexedDBの取得をカスタムhook化したもの
カスタムhookでやりたき事
- アイテムを選択(ローカルstateで値を保存)
- 選択したアイテムの情報をindexedDBから検索して返却
カスタムhookにuseLiveQueryを追加(失敗)
関数コンポーネントのサンプルをもとに、useLiveQuery()で取得したデータをsetSteteに代入しようとしたら、
戻り値がObservable<void>なので代入できません、というエラーがでた。
useXXX.ts
import React from "react";
import { useLiveQuery } from "dexie-react-hooks";
export const useXXX = () => {
const [selectedNo, setSelectedNo] = React.useState(false);
const [table, setTable] = React.useState([]);
const friends = Database.db.annotations.where({ No: selectedNo}).toArray(
React.useEffect(() => {
setTable(friends);
// 略
原因
Dexieのissuesでクラスコンポーネントで使いたい場合の質問と回答を発見。
-
useliveQuery
は関数コンポーネント(表示するエレメントをreturnで返す)にしか使えないのでliveQuery
を使う - componentDidMountで監視可能なliveQuery()にサブスクライブ
- componentWillUnmountでサブスクライブを解除
という実装で動くよう。
作成中のhookではcomponentDidMount()
は使っていないため、
useEffectでcomponentDidMount
とcomponentWillUnmount
に相当する実装を行った。
カスタムhookにuseLiveQueryを追加(成功)
useXXX.ts
import * as React from "react";
import { liveQuery } from "dexie";
// 略
// 引数にuseStateの値を使いたかったのでラップ
// 非同期にしないとobservableの戻り値がundifiendになった
const observableDb = (selectedNo) => {
const observable = liveQuery(async () => {
const returnValue = await Database.db.something.where({ No: selectedNo}).toArray();
return returnValue;
});
return observable;
};
export const useXXX = () => {
const [selectedNo, setSelectedNo] = React.useState(false);
const [store, setStore] = React.useState([]);
// indexedDBの戻り値をstateに保存
React.useEffect(() => {
const subscription = observableDb(selectedNo).subscribe(
result => setStore(result),
error => setStore([])
)
return () => { // componentWillUnmountに相当する
subscription.unsubscribe();
setStore([]);
}
}, [selectedNo]);// 第2引数を設定することでcomponentDidMountに相当する
// 略
Discussion