Skip to content

Conversation

@sukvvon
Copy link
Contributor

@sukvvon sukvvon commented Dec 14, 2025

🎯 Changes

Fixes #9610

When using HydrationBoundary with existing queries in the cache, an unnecessary refetch was triggered during hydration even though fresh data was about to be hydrated from the server.

Root Cause

  • useQuery's onSubscribe runs before HydrationBoundary's useEffect completes hydration
  • The query appears stale (before hydration), triggering an unnecessary refetch

Solution

  • Added pendingHydrationQueries WeakSet to track queries pending hydration
  • Mark existing queries as pending in useMemo (before children render)
  • Skip refetch in queryObserver.onSubscribe if query is pending hydration
  • Exception: refetchOnMount: 'always' still triggers refetch (user explicitly wants fresh data)
  • Clear pending flag in useEffect after hydration completes
  • Added cleanup function to clear pending flags on unmount

Files Changed

  • packages/query-core/src/hydration.ts - Export pendingHydrationQueries WeakSet
  • packages/query-core/src/index.ts - Re-export pendingHydrationQueries
  • packages/query-core/src/queryObserver.ts - Check pending hydration in onSubscribe
  • packages/react-query/src/HydrationBoundary.tsx - Mark/clear pending hydration queries with cleanup
  • packages/react-query/src/__tests__/HydrationBoundary.test.tsx - Add 14 test cases
  • docs/framework/react/guides/ssr.md - Document new behavior
  • docs/framework/react/reference/hydration.md - Document new behavior

✅ Checklist

  • I have followed the steps in the Contributing guide.
  • I have tested this code locally with pnpm run test:pr.

🚀 Release Impact

  • This change affects published code, and I have generated a changeset.
  • This change is docs/CI/dev-only (no release).

Summary by CodeRabbit

  • Bug Fixes

    • HydrationBoundary now prevents unnecessary refetches during hydration, avoiding double-fetch on page load and ensuring pending-hydration flags are cleared after hydration or on unmount.
  • Documentation

    • Clarified SSR and hydration guides: hydrated queries won't trigger an initial background refetch unless refetchOnMount is set to "always".
  • Tests

    • Added comprehensive tests for hydration flows, refetchOnMount variants, concurrent queries, cleanup, and edge cases.

✏️ Tip: You can customize this high-level summary in your review settings.

@changeset-bot
Copy link

changeset-bot bot commented Dec 14, 2025

🦋 Changeset detected

Latest commit: d3bf064

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

This PR includes changesets to release 19 packages
Name Type
@tanstack/query-core Patch
@tanstack/react-query Patch
@tanstack/angular-query-experimental Patch
@tanstack/query-async-storage-persister Patch
@tanstack/query-broadcast-client-experimental Patch
@tanstack/query-persist-client-core Patch
@tanstack/query-sync-storage-persister Patch
@tanstack/solid-query Patch
@tanstack/svelte-query Patch
@tanstack/vue-query Patch
@tanstack/react-query-devtools Patch
@tanstack/react-query-next-experimental Patch
@tanstack/react-query-persist-client Patch
@tanstack/angular-query-persist-client Patch
@tanstack/solid-query-persist-client Patch
@tanstack/svelte-query-persist-client Patch
@tanstack/solid-query-devtools Patch
@tanstack/svelte-query-devtools Patch
@tanstack/vue-query-devtools Patch

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

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 14, 2025

📝 Walkthrough

Walkthrough

Adds hydration-aware tracking to prevent double-fetch during HydrationBoundary hydration: introduces a WeakSet to mark pending queries, updates QueryObserver to skip fetches for pending queries (unless forced), updates HydrationBoundary to mark/clear pending queries, adds docs, tests, and a changeset.

Changes

Cohort / File(s) Summary
Core Hydration Tracking
packages/query-core/src/hydration.ts, packages/query-core/src/index.ts
Add and export pendingHydrationQueries: WeakSet<Query> to track queries awaiting hydration.
Query Observer Hydration Awareness
packages/query-core/src/queryObserver.ts
Import pendingHydrationQueries; compute hydration state in onSubscribe and skip initial fetch when a query is pending hydration (honoring refetchOnMount: 'always').
HydrationBoundary Implementation
packages/react-query/src/HydrationBoundary.tsx
Mark dehydrated queries as pending during render; clear pending flags after hydration/effect and on unmount to avoid stale flags and leaks.
Hydration Tests
packages/react-query/src/__tests__/HydrationBoundary.test.tsx
Add tests covering hydration timing, various refetchOnMount modes, concurrent queries, removals during hydration, and cleanup on unmount.
Documentation
docs/framework/react/guides/ssr.md, docs/framework/react/reference/hydration.md
Clarify that HydrationBoundary prevents unnecessary refetch during hydration unless refetchOnMount is 'always'.
Changeset
.changeset/fix-hydration-double-fetch.md
Add changeset noting patch bumps and the hydration refetch fix.

Sequence Diagram(s)

sequenceDiagram
    participant App as App / Router
    participant HB as HydrationBoundary
    participant QC as QueryClient / Cache
    participant QO as QueryObserver
    participant Net as Network

    rect rgba(230,240,255,0.5)
    Note over App,HB: Render phase (sync)
    App->>HB: Render with dehydrated state
    HB->>QC: Hydrate cache (useMemo)
    HB->>QC: For each hydrated query: add to pendingHydrationQueries
    Note over HB,QC: Queries flagged as pending
    end

    rect rgba(220,255,230,0.5)
    Note over QO,Net: Subscription / mount
    QO->>QO: onSubscribe runs
    QO->>QC: Check pendingHydrationQueries for query
    alt pending and refetchOnMount != 'always'
        QO->>QO: Skip initial fetch (avoid double-fetch)
    else not pending or refetchOnMount == 'always'
        QO->>Net: Fetch data
    end
    end

    rect rgba(255,250,220,0.5)
    Note over HB: Effect phase (async)
    HB->>HB: useEffect runs after paint
    HB->>QC: Complete hydration
    HB->>QC: clear pendingHydrationQueries for hydrated queries
    Note over HB,QC: Cleanup ensures no stale pending flags
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • TkDodo
  • manudeli

Poem

🐇 I nibble at fetches in the dawn's soft light,
A WeakSet keeps sleepy queries tight.
Hydration hops once, then rests with ease—
No double-calls, the server breathes. ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title directly and clearly describes the main fix: preventing unnecessary refetch during hydration in HydrationBoundary, which matches the core objective.
Linked Issues check ✅ Passed The PR successfully implements the fix for issue #9610: prevents unnecessary refetch during hydration by tracking pending queries and skipping refetch when appropriate.
Out of Scope Changes check ✅ Passed All changes are directly related to fixing the hydration double-fetch issue: core tracking mechanism, observer logic, boundary implementation, documentation updates, and comprehensive test coverage.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

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

@github-actions github-actions bot added documentation Improvements or additions to documentation package: react-query package: query-core labels Dec 14, 2025
@nx-cloud
Copy link

nx-cloud bot commented Dec 14, 2025

View your CI Pipeline Execution ↗ for commit d3bf064

Command Status Duration Result
nx affected --targets=test:sherif,test:knip,tes... ✅ Succeeded 4m 10s View ↗
nx run-many --target=build --exclude=examples/*... ✅ Succeeded 2s View ↗

☁️ Nx Cloud last updated this comment at 2026-01-17 03:20:46 UTC

@sukvvon sukvvon force-pushed the fix/hydration-boundary-double-fetch branch from 86745a3 to 8626d42 Compare December 14, 2025 17:56
@pkg-pr-new
Copy link

pkg-pr-new bot commented Dec 14, 2025

More templates

@tanstack/angular-query-experimental

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

@tanstack/eslint-plugin-query

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

@tanstack/query-async-storage-persister

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

@tanstack/query-broadcast-client-experimental

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

@tanstack/query-core

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

@tanstack/query-devtools

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

@tanstack/query-persist-client-core

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

@tanstack/query-sync-storage-persister

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

@tanstack/react-query

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

@tanstack/react-query-devtools

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

@tanstack/react-query-next-experimental

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

@tanstack/react-query-persist-client

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

@tanstack/solid-query

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

@tanstack/solid-query-devtools

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

@tanstack/solid-query-persist-client

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

@tanstack/svelte-query

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

@tanstack/svelte-query-devtools

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

@tanstack/svelte-query-persist-client

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

@tanstack/vue-query

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

@tanstack/vue-query-devtools

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

commit: d3bf064

@codecov
Copy link

codecov bot commented Dec 14, 2025

Codecov Report

❌ Patch coverage is 95.45455% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 59.97%. Comparing base (3e4f8c8) to head (d3bf064).

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##             main    #9968       +/-   ##
===========================================
+ Coverage   46.05%   59.97%   +13.92%     
===========================================
  Files         200      129       -71     
  Lines        8542     5769     -2773     
  Branches     1979     1591      -388     
===========================================
- Hits         3934     3460      -474     
+ Misses       4150     1994     -2156     
+ Partials      458      315      -143     
Components Coverage Δ
@tanstack/angular-query-experimental 93.85% <ø> (ø)
@tanstack/eslint-plugin-query ∅ <ø> (∅)
@tanstack/query-async-storage-persister 43.85% <ø> (ø)
@tanstack/query-broadcast-client-experimental 24.39% <ø> (ø)
@tanstack/query-codemods ∅ <ø> (∅)
@tanstack/query-core 97.83% <88.88%> (-0.05%) ⬇️
@tanstack/query-devtools 3.38% <ø> (ø)
@tanstack/query-persist-client-core 80.00% <ø> (ø)
@tanstack/query-sync-storage-persister 84.61% <ø> (ø)
@tanstack/query-test-utils ∅ <ø> (∅)
@tanstack/react-query 96.86% <100.00%> (+0.13%) ⬆️
@tanstack/react-query-devtools 9.25% <ø> (ø)
@tanstack/react-query-next-experimental ∅ <ø> (∅)
@tanstack/react-query-persist-client 100.00% <ø> (ø)
@tanstack/solid-query 77.81% <ø> (ø)
@tanstack/solid-query-devtools 64.17% <ø> (ø)
@tanstack/solid-query-persist-client 100.00% <ø> (ø)
@tanstack/svelte-query ∅ <ø> (∅)
@tanstack/svelte-query-devtools ∅ <ø> (∅)
@tanstack/svelte-query-persist-client ∅ <ø> (∅)
@tanstack/vue-query 71.91% <ø> (ø)
@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.

@sukvvon sukvvon force-pushed the fix/hydration-boundary-double-fetch branch from cfa5d74 to 695fa28 Compare December 27, 2025 17:38
@sukvvon sukvvon marked this pull request as ready for review December 29, 2025 14:28
@tarasvarshava
Copy link

Thanks a lot for this. I hope it gets merged soon 🤞

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation package: query-core package: react-query

Projects

None yet

Development

Successfully merging this pull request may close these issues.

HydrationBoundary double fetching on subsequent visits

2 participants