From 9ce863d2996c566ae78e5bcafaf26627180400ae Mon Sep 17 00:00:00 2001 From: Axel Bocciarelli Date: Mon, 3 Jun 2024 15:02:07 +0200 Subject: [PATCH] Cache child entities in fetch store instead of custom cache --- packages/app/src/providers/DataProvider.tsx | 11 ++----- packages/shared/src/react-suspense-fetch.ts | 33 +++++++++++---------- 2 files changed, 19 insertions(+), 25 deletions(-) diff --git a/packages/app/src/providers/DataProvider.tsx b/packages/app/src/providers/DataProvider.tsx index 4373e6d6f..34eba352d 100644 --- a/packages/app/src/providers/DataProvider.tsx +++ b/packages/app/src/providers/DataProvider.tsx @@ -1,5 +1,5 @@ import { isGroup } from '@h5web/shared/guards'; -import type { ChildEntity, Entity, Group } from '@h5web/shared/hdf5-models'; +import type { Entity } from '@h5web/shared/hdf5-models'; import { getNameFromPath } from '@h5web/shared/hdf5-utils'; import { createFetchStore } from '@h5web/shared/react-suspense-fetch'; import type { PropsWithChildren } from 'react'; @@ -43,21 +43,14 @@ function DataProvider(props: PropsWithChildren) { const { api, children } = props; const entitiesStore = useMemo(() => { - const childCache = new Map>(); - const store = createFetchStore(async (path: string) => { - const cachedEntity = childCache.get(path); - if (cachedEntity) { - return cachedEntity; - } - const entity = await api.getEntity(path); if (isGroup(entity)) { // Cache non-group children (datasets, datatypes and links) entity.children.forEach((child) => { if (!isGroup(child)) { - childCache.set(child.path, child); + store.preset(child.path, child); } }); } diff --git a/packages/shared/src/react-suspense-fetch.ts b/packages/shared/src/react-suspense-fetch.ts index 9e2371d82..2d02d5449 100644 --- a/packages/shared/src/react-suspense-fetch.ts +++ b/packages/shared/src/react-suspense-fetch.ts @@ -13,15 +13,16 @@ interface Instance { export interface FetchStore { prefetch: (input: Input) => void; get: (input: Input) => Result; + preset: (input: Input, result: Result) => void; evict: (input: Input) => void; abort: (input: Input) => void; } export function createFetchStore( fetchFunc: FetchFunc, - areEqual?: AreEqual, + areEqual: AreEqual = Object.is, ) { - const cache = createCache(areEqual); + const cache = createCache>(areEqual); return { prefetch: (input: Input): void => { @@ -34,6 +35,14 @@ export function createFetchStore( cache.set(input, instance); return instance.get(); }, + preset: (input: Input, result: Result): void => { + cache.set(input, { + get: () => result, + abort: () => { + /* noop */ + }, + }); + }, evict: (input: Input): void => { cache.delete(input); }, @@ -43,15 +52,7 @@ export function createFetchStore( }; } -function createCache(areEqual?: AreEqual) { - if (!areEqual) { - return new Map>(); - } - - return createMapLikeWithComparator>(areEqual); -} - -function createMapLikeWithComparator(areEqual: AreEqual) { +function createCache(areEqual: AreEqual) { const map = new Map(); return { @@ -88,9 +89,9 @@ function createInstance( input: Input, fetchFunc: FetchFunc, ): Instance { - let promise: Promise | null = null; - let result: Result | null = null; - let error: unknown = null; + let promise: Promise | undefined; + let result: Result | undefined; + let error: unknown; const controller = new AbortController(); promise = (async () => { @@ -99,7 +100,7 @@ function createInstance( } catch (error_) { error = error_; } finally { - promise = null; + promise = undefined; } })(); @@ -108,7 +109,7 @@ function createInstance( if (promise) { throw promise; // eslint-disable-line @typescript-eslint/no-throw-literal } - if (error !== null) { + if (error !== undefined) { throw error; // eslint-disable-line @typescript-eslint/no-throw-literal } return result as Result;