Repository navigation
Conversation
🚀 Changeset Version Preview3 package(s) bumped directly, 21 bumped as dependents. 🟨 Minor bumps
🟩 Patch bumps
|
cursor
Bot
force-pushed
the
cursor/query-handles-devtools-271e
branch
3 times, most recently
from
November 2, 2026 01:03
86bcf1d to
0b6a5aa
Compare
3 of 5 tasks
cursor
Bot
force-pushed
the
cursor/query-handles-devtools-271e
branch
from
November 2, 2026 14:11
0b6a5aa to
b842101
Compare
3 of 5 tasks
cursor
Bot
force-pushed
the
cursor/query-handles-devtools-271e
branch
5 times, most recently
from
November 2, 2026 19:48
83ccbd6 to
d778587
Compare
…r queries in the devtools Co-authored-by: alexander <alexander@n1s.se>
…nfo tests with 'using' Adds the 'subscribe' helper to @tanstack/query-test-utils, as in the hydrated rejection retry PR, and uses query-test-utils in query-devtools instead of a local 'clearOnDispose'. Console spies are held with 'using' too. Co-authored-by: alexander <alexander@n1s.se>
… copy Co-authored-by: alexander <alexander@n1s.se>
…n less Track waterfall handles in a WeakSet, so a Server Component can pass them on. dehydrate now warns once per query, only on the server, and not for queries an earlier dehydrate sent. A start on fresh data notifies the cache, so the devtools show it, and hydrate only restores start info in development. Co-authored-by: alexander <alexander@n1s.se>
Production builds add no cache listener and wrap no queryFn. Co-authored-by: alexander <alexander@n1s.se>
cursor
Bot
force-pushed
the
cursor/experimental-query-handles-271e
branch
from
November 2, 2026 20:00
e3a2b96 to
b6bc296
Compare
cursor
Bot
force-pushed
the
cursor/query-handles-devtools-271e
branch
from
November 2, 2026 20:02
d778587 to
f639acc
Compare
Owner
Author
|
Moved to TanStack#12513. |
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.
This PR builds on #2 (experimental query handles) and targets its branch. It's a separate PR to keep #2's core changes small.
🎯 Changes
Core records start info only in development. In a production build, the handle functions return the factory's options untouched, add no cache listener and wrap no
queryFn, andexperimental_getQueryStartInforeturnsundefined.query-core
Symbol.for('@tanstack/query-core/experimental_start')key on theQueryobject, because the devtools bundle their own copy of query-core and wouldn't see a module-level map.experimental_getQueryStartInfo(query)reads it, andexperimental_QueryStartInfotypes it. A start on fresh data fetches nothing, so recording it emits anobserverResultsUpdatedcache event, which tells the devtools to read the new record.experimental_waterfallHandlestarts nothing, so in development core keeps its handles in a module-levelWeakSetinstead. The handles stay plain{ queryKey, input }objects with no symbol properties, so a Server Component can pass them to a Client Component. For a handle in the set,experimental_fromHandlewraps the options'queryFn, so the query records the reader's first fetch with the verbwaterfallHandle. Refetches don't overwrite that record, and when the switch form returns the loader's own handle, the loader's record stays.dehydrateincludes the start info asexperimental_start, andhydraterestores it withobserved: false, so a hydrated query keeps the server's record.dehydrateon the server warns once when it leaves out a pending query thatexperimental_prefetchHandle,experimental_ensureHandleorexperimental_fetchHandlestarted there, since the browser would fetch it again. Queries an earlierdehydratecall sent don't count, so the guide's nested-dehydration pattern andReactQueryStreamedHydrationdon't warn, and neither does a browserdehydrateof a hydrated query. The warning belongs here rather than in feat(query-core, react-query): add experimental query handles #2 because it needs the start info to know which function started the query, and where.query-devtools
waterfallbadge, also in the row's aria-label, on queries that a reader of anexperimental_waterfallHandlehandle first fetched.experimental_getQueryStartInfofrom their own copy of query-core, which finds the same registered symbol. The build only bundles that one function.Docs
The query handles guide gains a sentence on the dev warning, a mention of the waterfall badge, and a Devtools section, which says that production builds record nothing, so the devtools show none of it there.
Tests
queryStartInfo.test.tsxcovers recording andobserved, the waterfall reader's first fetch, waterfall handles with no symbol properties, a switched-back loader handle, the cache event for a start on fresh data, start info thatresetQuerieskeeps, queries that other APIs start, the record moving from server to client, and when the warning shows: once per query, not for queries an earlierdehydratesent, and not when the browser dehydrates a hydrated query. Two tests stubNODE_ENVtoproductionand check that nothing is recorded, thequeryFnisn't wrapped, and the cache has no listener. TheDehydratedQuerykey-set type test covers the new field.waterfallHandletest also checks that the query records a suspense reader's fetch and marks it as read.using:subscribe(observer, noop)unsubscribes observers,unmountOnDispose(...)unmounts renders, theconsole.warnspies dispose themselves, and aproductionEnvironment()helper restoresNODE_ENV. query-devtools now uses@tanstack/query-test-utilsas a dev dependency instead of its ownclearOnDispose.Screenshots
These come from a small React app running in development mode. Its loader awaits the viewer with
experimental_ensureHandle, and prefetches page 1 of the posts and the stats withexperimental_prefetchHandle. The page reads the viewer and the posts withexperimental_fromHandle, and never reads the stats. "Next page" switches the posts handle withexperimental_waterfallHandle.Before the switch, Query Details shows that
prefetchHandlestarted page 1:The loader prefetched the stats, but no component read them:
After the switch, page 2 has the
waterfallbadge, and Query Details shows thatwaterfallHandlestarted it:The whole flow:
✅ Checklist
pnpm run test:pr, or these tests do not apply to this pull request. (Ran oxlint, knip,test:typesacross all TS versions, and vitest for query-core, query-devtools, react-query and query-test-utils, plus the docs link check.)🚀 Release Impact