Dataset tab switches render instantly from a shared curated cache - #157
Merged
Conversation
/api/search sends no Cache-Control, so the browser never reuses the request, and Homepage is a plain top-level route that fully unmounts on tab switch. Every Team/Overview -> Dataset switch paid a fresh network round trip plus a loading-spinner flash, even though the curated grid is deterministic and the existing idle warm-up had just fetched the same data moments earlier and thrown the result away (it only used it to preload images). Add helpers/curatedCache.ts as the single source of truth for that fetch: a module-scope cache both the app-boot warm-up and useDashboard's mount effect read/write, de-duped via an in-flight promise. useDashboard now seeds its initial state from the cache via a lazy useState initializer when present, so a warm tab switch renders the grid on the very first paint with no skeleton and no request. Cold loads (first visit before the warm-up settles, or a real fetch failure) fall back to the previous fetch-and-wait behavior unchanged.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Team/Overview -> Dataset tab switches paid a full network round trip + loading-spinner flash every time, even though the curated grid is deterministic. Two causes:
/api/searchsends noCache-Control, so the browser never reuses the request.useDashboard's mount effect re-fetches from scratch every time.The existing idle warm-up (
prefetchCurated) already fetched the same curated data moments after app boot, but only used it to preload preview images and threw the JSON away — so it did nothing to prevent the refetch.What changed
helpers/curatedCache.ts(new): a module-scope cache that is the single source of truth for the curated (tumor/no-tumor, sort_by=quality) fetch. Both the app-boot warm-up anduseDashboard's mount effect read/write it, de-duped via an in-flight promise.useDashboard: seedspreviewIds/previewMetadata/loadingfrom the cache via a lazyuseStateinitializer when present, so a warm tab switch renders the grid on the very first paint — no skeleton, no request. Cold loads (first visit before warm-up settles, or a genuine fetch failure) fall back to the previous fetch-and-wait behavior unchanged. A total-failure response is not cached, so a transient network blip doesn't wedge the grid empty for the rest of the session.App.tsx: swapped the oldprefetchCuratedimport forwarmCuratedCache, same idle-callback timing.helpers/prefetchCurated.ts(superseded).Filtered/deep-linked searches are unaffected — only the no-filter curated view is cacheable.
Verified
npm run typecheckandnpm run buildboth clean (run in a scratch clone on bdmap1, not the prod checkout).