Skip to content

fix(react-router): render the pending document root only when its beforeLoad context exists - #8129

Open
antur84 wants to merge 1 commit into
TanStack:mainfrom
antur84:fix/hydration-uncommitted-root-context
Open

fix(react-router): render the pending document root only when its beforeLoad context exists#8129
antur84 wants to merge 1 commit into
TanStack:mainfrom
antur84:fix/hydration-uncommitted-root-context

Conversation

@antur84

@antur84 antur84 commented Aug 20, 2026

Copy link
Copy Markdown

Fixes #8128

Summary

  • contextualize (router-core) records __beforeLoadContext when a client beforeLoad settles, mirroring load-server (a void return records {}, so it still counts as settled)
  • hydrate() restores __beforeLoadContext from the dehydrated b for committed matches
  • Match.tsx's document-root pending exception renders the real component only when the route has no beforeLoad or the match's beforeLoad contribution exists — the condition the branch's own comment ("hydrated matches retain their prior data") already assumes
  • New regression test observes the render directly: a dehydrated root with an id skew renders ['undefined', 'en'] without this change, ['en'] with it

Verification

Summary by CodeRabbit

  • Bug Fixes

    • Improved SSR hydration when routes use asynchronous loading.
    • Prevented incomplete context from replacing the document root during hydration.
    • Ensured route context is restored consistently before rendering nested content.
  • Tests

    • Added regression coverage for hydration scenarios involving asynchronous root loading and server-rendered data.

…oreLoad context exists

The document-root pending exception keeps rendering the real component
because pending UI would remove <html> and hydrated matches retain their
prior data. An uncommitted hydrated root has no prior data: hydrate() only
merges the dehydrated beforeLoad context (b) for committed matches, so an
id-mismatched or stale root renders with every beforeLoad-provided context
key missing (TanStack#8115's production symptom, still present with TanStack#8116).

Track beforeLoad settlement on the client (__beforeLoadContext, mirroring
load-server) and via the dehydrated b for committed hydration, and gate the
document-root exception on it.
@coderabbitai

coderabbitai Bot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 84d7dba6-9d25-4b95-b80e-34de3dd67418

📥 Commits

Reviewing files that changed from the base of the PR and between e9f63a6 and fba7a18.

📒 Files selected for processing (3)
  • packages/react-router/src/Match.tsx
  • packages/react-router/tests/issue-8115-hydration-context-window.test.tsx
  • packages/router-core/src/load-client.ts

Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review.


📝 Walkthrough

Walkthrough

The router now stores and restores beforeLoad context during hydration. MatchInner delays retained SSR root rendering when that context is not available. A regression test covers mismatched hydration data and asynchronous root loading.

Changes

Hydration context handling

Layer / File(s) Summary
Restore beforeLoad context
packages/router-core/src/load-client.ts
Client loading stores beforeLoad results on matches. Hydration restores serialized beforeLoad context, using an empty object when no context exists.
Gate SSR root rendering
packages/react-router/src/Match.tsx, packages/react-router/tests/issue-8115-hydration-context-window.test.tsx
MatchInner retains SSR output only when required beforeLoad context is available. The regression test verifies that the root receives locale before the index route renders.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Merge Risk: ⚪ Minimal · up to fba7a

This localized hydration fix is merge-ready after normal checks and review; no actionable merge-blocking risk remains.

Possibly related PRs

Suggested labels: package: react-router, package: router-core

Suggested reviewers: sheraff

🚥 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 title clearly describes the primary change: gating pending document-root rendering on available beforeLoad context.
Linked Issues check ✅ Passed The changes track and restore beforeLoad context, gate unsafe root rendering, and add a regression test for issue #8128.
Out of Scope Changes check ✅ Passed All code and test changes directly support hydration context preservation and safe document-root rendering.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Hydration renders the document root with beforeLoad-provided context stripped when the root fails commitment

1 participant