Skip to content

fix(core): observing "promise" needs to implicitly observe "data" - #9772

Merged
TkDodo merged 3 commits into
mainfrom
feature/fix/use-data
Oct 16, 2025
Merged

fix(core): observing "promise" needs to implicitly observe "data"#9772
TkDodo merged 3 commits into
mainfrom
feature/fix/use-data

Conversation

@TkDodo

@TkDodoTkDodo commented Oct 16, 2025

Copy link
Copy Markdown
Collaborator

fixes#9727

Summary by CodeRabbit

  • Bug Fixes

    • Promise observation now implicitly observes associated data, fixing tracking and ensuring correct query results (including infinite queries).
  • New Features

    • Exported infinite-query hook made available from the public API.
  • Tests

    • Added tests verifying promise-driven observation correctly tracks data and renders pagination/loading states.
  • Chores

    • Added a changeset entry for a patch bump noting the observation fix.

@changeset-bot

changeset-botBot commented Oct 16, 2025

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: e6fce97

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 19 packages
NameType
@tanstack/query-corePatch
@tanstack/angular-query-experimentalPatch
@tanstack/query-async-storage-persisterPatch
@tanstack/query-broadcast-client-experimentalPatch
@tanstack/query-persist-client-corePatch
@tanstack/query-sync-storage-persisterPatch
@tanstack/react-queryPatch
@tanstack/solid-queryPatch
@tanstack/svelte-queryPatch
@tanstack/vue-queryPatch
@tanstack/angular-query-persist-clientPatch
@tanstack/react-query-persist-clientPatch
@tanstack/solid-query-persist-clientPatch
@tanstack/svelte-query-persist-clientPatch
@tanstack/react-query-devtoolsPatch
@tanstack/react-query-next-experimentalPatch
@tanstack/solid-query-devtoolsPatch
@tanstack/svelte-query-devtoolsPatch
@tanstack/vue-query-devtoolsPatch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@TkDodo
TkDodo marked this pull request as ready for review October 16, 2025 13:34
@coderabbitai

coderabbitaiBot commented Oct 16, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

Accessing a proxied query result's promise now also explicitly tracks data. A changeset was added documenting a patch bump for @tanstack/query-core. Tests were updated/added to assert implicit data observation when using the promise (including infinite-query hasNextPage scenarios).

Changes

Cohort / File(s)Summary
Changeset metadata
\.changeset/good-windows-tell.md``
New changeset entry documenting a patch bump for @tanstack/query-core and a fix note: "observing 'promise' needs to implicitly observe 'data'."
Query observer proxy tracking
packages/query-core/src/queryObserver.ts
Reorganized proxy get handler for promise: when promise is accessed it now explicitly tracks data in that branch and preserves the existing conditional rejection of a pending thenable when experimental_prefetchInRender is disabled.
Tests & public export usage
packages/react-query/src/__tests__/useQuery.promise.test.tsx
Added imports and tests verifying "should implicitly observe data when promise is used"; updated expectations and flows (including infinite-query hasNextPage) to reflect implicit data observation. Tests reference useInfiniteQuery (export surface used in tests).

Sequence Diagram(s)

sequenceDiagram
autonumber
participant Component as React component
participant Proxy as QueryObserver Proxy
participant Observer as QueryObserver internals
participant Thenable as Query.thenable
Component->>Proxy: access `query.promise` (e.g. use(query.promise))
note right of Proxy #D6EAF8: proxy.get('promise') updated
Proxy->>Observer: track('data') ## explicit tracking added
alt thenable pending and !experimental_prefetchInRender
Observer->>Thenable: reject/throw pending thenable
note right of Thenable #FDEBD0: triggers Suspense / error path
else
Observer->>Thenable: return thenable (normal path)
note right of Thenable #E8F8F5: component can await/use data
end
Thenable-->>Component: resolved/rejected result
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 I tapped the promise, data stirred from its bed,
Now both wake together when use is said.
hasNextPage hums, no longer astray,
Suspense tips its hat and hops away. ✨

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check nameStatusExplanationResolution
Description Check⚠️ WarningThe description only contains “fixes #9727” and omits the required sections for “Changes”, “Checklist”, and “Release Impact” from the repository template, so it does not follow the prescribed structure or provide context about the change.Please expand the PR description to include the “🎯 Changes” section with details on what was modified and why, complete the “✅ Checklist” confirming contribution and testing steps, and fill out “🚀 Release Impact” to indicate changeset generation or dev-only impact.
Docstring Coverage⚠️ WarningDocstring coverage is 0.00% which is insufficient. The required threshold is 80.00%.You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (3 passed)
Check nameStatusExplanation
Title Check✅ PassedThe title clearly summarizes the primary change by indicating that observing the promise property will now implicitly observe data, matching the core fix implemented in the changeset and code. It is concise, specific to the main change, and follows conventional commit style without extraneous information.
Linked Issues Check✅ PassedThe code updates ensure that accessing promise now also tracks data and related properties, directly addressing the core issue of stale hasNextPage after suspension described in issue #9727. Tests were added and updated to verify implicit data observation via promise.
Out of Scope Changes Check✅ PassedAll modifications—including the changeset metadata, core logic in queryObserver.ts, and related tests—are focused on ensuring that observing promise implicitly observes data, which aligns with the linked issue objectives. No unrelated functionality or files appear to have been altered.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/fix/use-data

Comment @coderabbitai help to get the list of available commands and usage tips.

@nx-cloud

nx-cloudBot commented Oct 16, 2025

Copy link
Copy Markdown

View your CI Pipeline Execution ↗ for commit e6fce97

CommandStatusDurationResult
nx affected --targets=test:sherif,test:knip,tes...✅ Succeeded3m 13sView ↗
nx run-many --target=build --exclude=examples/*...✅ Succeeded28sView ↗

☁️ Nx Cloud last updated this comment at 2025-10-16 14:23:13 UTC

@pkg-pr-new

pkg-pr-newBot commented Oct 16, 2025

Copy link
Copy Markdown
More templates

@tanstack/angular-query-experimental

npm i https://pkg.pr.new/@tanstack/angular-query-experimental@9772

@tanstack/eslint-plugin-query

npm i https://pkg.pr.new/@tanstack/eslint-plugin-query@9772

@tanstack/query-async-storage-persister

npm i https://pkg.pr.new/@tanstack/query-async-storage-persister@9772

@tanstack/query-broadcast-client-experimental

npm i https://pkg.pr.new/@tanstack/query-broadcast-client-experimental@9772

@tanstack/query-core

npm i https://pkg.pr.new/@tanstack/query-core@9772

@tanstack/query-devtools

npm i https://pkg.pr.new/@tanstack/query-devtools@9772

@tanstack/query-persist-client-core

npm i https://pkg.pr.new/@tanstack/query-persist-client-core@9772

@tanstack/query-sync-storage-persister

npm i https://pkg.pr.new/@tanstack/query-sync-storage-persister@9772

@tanstack/react-query

npm i https://pkg.pr.new/@tanstack/react-query@9772

@tanstack/react-query-devtools

npm i https://pkg.pr.new/@tanstack/react-query-devtools@9772

@tanstack/react-query-next-experimental

npm i https://pkg.pr.new/@tanstack/react-query-next-experimental@9772

@tanstack/react-query-persist-client

npm i https://pkg.pr.new/@tanstack/react-query-persist-client@9772

@tanstack/solid-query

npm i https://pkg.pr.new/@tanstack/solid-query@9772

@tanstack/solid-query-devtools

npm i https://pkg.pr.new/@tanstack/solid-query-devtools@9772

@tanstack/solid-query-persist-client

npm i https://pkg.pr.new/@tanstack/solid-query-persist-client@9772

@tanstack/svelte-query

npm i https://pkg.pr.new/@tanstack/svelte-query@9772

@tanstack/svelte-query-devtools

npm i https://pkg.pr.new/@tanstack/svelte-query-devtools@9772

@tanstack/svelte-query-persist-client

npm i https://pkg.pr.new/@tanstack/svelte-query-persist-client@9772

@tanstack/vue-query

npm i https://pkg.pr.new/@tanstack/vue-query@9772

@tanstack/vue-query-devtools

npm i https://pkg.pr.new/@tanstack/vue-query-devtools@9772

commit: e6fce97

@github-actions

github-actionsBot commented Oct 16, 2025

Copy link
Copy Markdown
Contributor

Sizes for commit e6fce97:

BranchBundle Size
Main
This PR

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
packages/react-query/src/__tests__/useQuery.promise.test.tsx (1)

1388-1433: Well-crafted test that validates the fix for issue #9727.

The test correctly verifies that accessing query.promise via React.use() now implicitly tracks data, ensuring that hasNextPage (which depends on the tracked data) reflects the correct value after suspending. The query setup, suspense handling, and assertions are all appropriate.

Optional suggestions for enhanced clarity:

  • Consider adding a brief inline comment before line 1405 explaining that this test specifically validates implicit data observation when using the promise (e.g., // Accessing promise should implicitly track data, ensuring hasNextPage is correctly computed).
  • For completeness, you could add a complementary test case that verifies hasNextPage: false when getNextPageParam returns null or undefined.
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0a72df8 and a7e6603.

📒 Files selected for processing (1)
  • packages/react-query/src/__tests__/useQuery.promise.test.tsx (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
packages/react-query/src/__tests__/useQuery.promise.test.tsx (2)
packages/query-core/src/queryObserver.ts (1)
  • query (704-721)
packages/query-core/src/infiniteQueryBehavior.ts (1)
  • hasNextPage (162-168)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Preview
  • GitHub Check: Test

@codecov

codecovBot commented Oct 16, 2025

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 16.66667% with 5 lines in your changes missing coverage. Please review.
✅ Project coverage is 59.77%. Comparing base (64507ba) to head (e6fce97).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files

Impacted file tree graph

@@ Coverage Diff @@## main #9772 +/- ##
===========================================
+ Coverage 45.75% 59.77% +14.02% 
===========================================
Files 200 129 -71 Lines 8403 5619 -2784 Branches 1930 1537 -393 ===========================================
- Hits 3845 3359 -486 + Misses 4111 1955 -2156 + Partials 447 305 -142 
ComponentsCoverage Δ
@tanstack/angular-query-experimental93.85% <ø> (ø)
@tanstack/eslint-plugin-query∅ <ø> (∅)
@tanstack/query-async-storage-persister43.85% <ø> (ø)
@tanstack/query-broadcast-client-experimental24.39% <ø> (ø)
@tanstack/query-codemods∅ <ø> (∅)
@tanstack/query-core97.37% <16.66%> (-0.12%)⬇️
@tanstack/query-devtools3.48% <ø> (ø)
@tanstack/query-persist-client-core80.00% <ø> (ø)
@tanstack/query-sync-storage-persister84.61% <ø> (ø)
@tanstack/query-test-utils∅ <ø> (∅)
@tanstack/react-query96.01% <ø> (ø)
@tanstack/react-query-devtools10.00% <ø> (ø)
@tanstack/react-query-next-experimental∅ <ø> (∅)
@tanstack/react-query-persist-client100.00% <ø> (ø)
@tanstack/solid-query78.06% <ø> (ø)
@tanstack/solid-query-devtools61.90% <ø> (ø)
@tanstack/solid-query-persist-client100.00% <ø> (ø)
@tanstack/svelte-query∅ <ø> (∅)
@tanstack/svelte-query-devtools∅ <ø> (∅)
@tanstack/svelte-query-persist-client∅ <ø> (∅)
@tanstack/vue-query71.10% <ø> (ø)
@tanstack/vue-query-devtools∅ <ø> (∅)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
packages/react-query/src/__tests__/useQuery.promise.test.tsx (2)

420-423: Brittle renderedComponents ordering assertions

Adjustments to expect(renderedComponents).toEqual([Page, MyComponent]) look correct functionally, but strict array equality on render order can be flaky across React versions/runtimes. Consider relaxing:

  • Assert presence instead of exact order: expect(renderedComponents).toEqual(expect.arrayContaining([Page, MyComponent])) and assert length
  • Or assert DOM output only (already done in most tests)

Also applies to: 488-491, 682-685, 1097-1100, 1111-1114


1287-1294: Make background-update assertion deterministic under fake timers

The new waitFor is reasonable, but with vi.useFakeTimers shouldAdvanceTime: true, polling can still be timing-sensitive. Prefer explicit timer advancement + stream take to reduce flakiness.

Apply this diff:

- {- const { snapshot } = await renderStream.takeRender()- expect(snapshot).toMatchObject({ data: 'test3' })- }+ {+ const { snapshot } = await renderStream.takeRender()+ expect(snapshot).toMatchObject({ data: 'test3' })+ }- await waitFor(() => rendered.getByText('test0new'))+ await vi.advanceTimersByTimeAsync(10)+ {+ const { withinDOM } = await renderStream.takeRender()+ withinDOM().getByText('test0new')+ }

If you prefer keeping waitFor, consider jest/rtl timer config to ensure it integrates with vitest fake timers in CI.

Also applies to: 1302-1303

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a7e6603 and e6fce97.

📒 Files selected for processing (1)
  • packages/react-query/src/__tests__/useQuery.promise.test.tsx (9 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
packages/react-query/src/__tests__/useQuery.promise.test.tsx (2)
packages/query-core/src/queryObserver.ts (1)
  • query (704-721)
packages/query-core/src/infiniteQueryBehavior.ts (1)
  • hasNextPage (162-168)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Preview
  • GitHub Check: Test
🔇 Additional comments (3)
packages/react-query/src/__tests__/useQuery.promise.test.tsx (3)

9-9: Confirm peer dependency for waitFor

Using waitFor from @testing-library/react 16.x requires @testing-library/dom as a peer. Ensure it’s installed to avoid runtime/typings issues in CI.

Based on learnings


15-17: Public export of useInfiniteQuery

Importing useInfiniteQuery from the package barrel implies it’s exported publicly. Please confirm the export is present in the public module to keep tests (and consumers) aligned.


1385-1430: Great coverage: implicit data observation via promise

This precisely captures the regression for infinite queries (hasNextPage becomes true after suspension). LGTM.

@TkDodo
TkDodo merged commit e42ddfe into mainOct 16, 2025
8 of 9 checks passed
@TkDodo
TkDodo deleted the feature/fix/use-data branch October 16, 2025 15:07
@github-actionsgithub-actionsBot mentioned this pull request Oct 16, 2025
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unexpected behaviour involving tracked properties and React's use function

1 participant

@TkDodo