我想在 UseLiveQuery 未完成时显示加载程序,并在 UseLiveQuery 返回空数组时显示“未找到组件”。
有没有简单的方法可以做到这一点?
非常感谢。
当您的查询器返回一个数组时,这是最简单的(见下文)。那么未定义的结果意味着仍在加载,而空数组意味着已完成加载但结果为零。
const friends = useLiveQuery (() => db.friends.toArray());
if (!friends) return <Spinner />; // Still loading
return <ul>{
friends.map(friend => <li key={friend.id}>
{friend.name}, {friend.age}
</li>)
}</ul>;
但是,如果您的查询器从 table.get() 返回结果,则未定义的值可能意味着查询仍在加载或未找到请求的 id。为了区分两者,您可以让查询器返回一些内容,以便更容易区分两者。例如,让查询器将结果作为数组中的项目返回,并为 useLiveQuery() 提供第三个参数,并使用空数组(未定义的其他内容)作为默认结果。
const [friend, loaded] = useLiveQuery (
() => db.friends.get(1).then(friend => [friend, true]),
[], // deps...
[] // default result: makes 'loaded' undefined while loading
);
if (!loaded) return <Spinner />; // Still loading...
if (!friend) return <NotFound ... />; // Loaded but friend not found
return <>{friend.name}, {friend.age}</>; // Loaded and friend found.
也就是说,在查询 indexedDB 时通常不需要微调器(除非非常复杂的查询)。在这种情况下,最好只返回
null
而不是 <Spinner />
,这样可以最小化最终用户的麻烦。
我创建了一个包装器 (React) 钩子来通过 Dexie.js 提供这种行为。它完全使用 TypeScript 进行键入。 它还会考虑丢失的数据(例如,如果您 .get() 使用 IndexedDB 中不存在的键),并且在处理数组时具有不同的返回类型(因为在这种情况下,我们永远不会有未定义的数据结果)。
import {MySubClassedDexie, useDexieDb} from "@/providers/dexieProvider/dexieProvider";
import {useLiveQuery} from "dexie-react-hooks";
export enum Status {
PENDING = 'pending',
RESOLVED = 'resolved'
}
export type AsyncLiveQueryReturn<T = any> = AsyncLiveQueryReturnPending | AsyncLiveQueryReturnResolved<T>;
export interface AsyncLiveQueryReturnPending {
isLoading: true;
isSuccess: false;
status: Status.PENDING;
data: null;
}
export interface AsyncLiveQueryReturnResolved<T = any> {
isLoading: false;
isSuccess: true;
status: Status.RESOLVED;
data: T extends Array<infer U> ? Array<U> : (T | undefined);
}
const useAsyncLiveQuery = <T>(querier: (db: MySubClassedDexie) => Promise<T>, deps: any[] = [], defaultIfMissing?: T): AsyncLiveQueryReturn<T> => {
const db = useDexieDb();
const [data, status] = useLiveQuery(() => {
return querier(db).then((data: T) => {
const d = data === undefined ? defaultIfMissing : data;
return [d, Status.RESOLVED]
})
}, deps, [null, Status.PENDING])
return {
isLoading: status === Status.PENDING,
isSuccess: status === Status.RESOLVED,
status,
data,
} as AsyncLiveQueryReturn<T>;
};
export default useAsyncLiveQuery;
您可以按如下方式使用它:
const {isLoading, isSuccess, data} = useAsyncLiveQuery(db => db.items.get(myId), [myId], myFallbackObject);
我希望这对某人有帮助!
了解 Vue 中是否加载或未找到的简单方法:
const item = useObservable(Dexie.liveQuery(() => db.items.get(id.value).then(o => o || null)))
// Handle not found (undefined = still loading, null = not found)
watch(item, (newItem) => {
if (newItem === null) {
// HANDLE NOT FOUND
}
})