Repository navigation
perf(fetchium): hydrate synchronously from a sync store - #69
Merged
abedell-phantom merged 9 commits intoOct 8, 2026
Merged
abedell-phantom merged 9 commits into
abedell-phantom merged 9 commits into
Conversation
This was referenced Oct 5, 2026
abedell-phantom
marked this pull request as ready for review
October 5, 2026 14:11
abedell-phantom
added this pull request to stack #72
October 5, 2026 19:51
… first fetch on a microtask A query activated against SyncQueryStore (MMKV on mobile) resolved with its cached value a microtask after activation, so the first React render showed a loading state and a second, sync-lane render showed the data. The first fetch then waited on setTimeout(0). Apply the cached value in the activating read when the store returns synchronously, and run the subscription and first fetch on a microtask, still outside the relay's computation. AsyncQueryStore keeps its async path. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Lead with what changes for an app using useQuery or fetchQuery, keep migration notes to a line or two, and drop internal detail. No source change. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
abedell-phantom
force-pushed
the
perf/sync-hydrate-first-fetch
branch
from
October 6, 2026 17:01
1cc0908 to
e28c770
Compare
invalidateQueries() sets updatedAt to 0, but isStale only treated undefined as stale, so with staleTime: Infinity an uncached query invalidated before its first fetch started made no request and stayed pending. An invalidation made before the cache loaded is also kept now, instead of being overwritten by the cached timestamp. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…tely Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
jimmy-phantom
approved these changes
Oct 7, 2026
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
With a synchronous store (
SyncQueryStore, such as MMKV on React Native), a query still resolved its cached value a microtask after activation. A component mounting the query rendered a loading state first, then re-rendered with the cached data. The first fetch then waited asetTimeout(0), which on React Native can take a frame or more. In the Phantom wallet this showed up as a skeleton flash and an extra render on every warm screen open.What changed
SyncQueryStore, the cached value is applied inside the read that activates the query. The first render shows the cached data.setTimeout(0). Both still run outside the activating read.refetch()) is not duplicated.AsyncQueryStore, hydration still happens when the load resolves. The subscription and fetch now follow right away, without a timer hop.Behavior changes
isPendingturns true for the background refetch one microtask after activation. The cached value stays readable during the refetch.patch.Testing
sync-hydration.test.ts: sync store with fresh cache, stale cache and a miss; async store pending then hydrating, and fetching after a miss without a timer hop.react/sync-hydration.test.tsx:useQueryandcomponent()render cached data on the first render.caching-persistence.test.tsupdated for the earlier hydration.Stack: #67 → #64 → #61 → #69 (this) → #70 → #71.
🤖 Generated with Claude Code