Skip to content

fix(router-core): propagate beforeLoad context to sub-route while its loader reloads in the background#7603

Open
ulrichstark wants to merge 2 commits into
TanStack:mainfrom
ulrichstark:fix(router-core)--propagate-beforeLoad-context-to-sub-route-while-its-loader-reloads-in-the-background
Open

fix(router-core): propagate beforeLoad context to sub-route while its loader reloads in the background#7603
ulrichstark wants to merge 2 commits into
TanStack:mainfrom
ulrichstark:fix(router-core)--propagate-beforeLoad-context-to-sub-route-while-its-loader-reloads-in-the-background

Conversation

@ulrichstark

@ulrichstark ulrichstark commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Fixes #7602

Summary by CodeRabbit

  • Bug Fixes

    • Fixed an issue where context values set by a parent route were not properly available to child routes during background data reloads.
  • Tests

    • Added regression test to verify context propagation during background data reloading of child routes.

@coderabbitai

coderabbitai Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR fixes a bug where context values set by a parent route's beforeLoad were unavailable to child routes during background loader reloads. The fix adds an immediate context synchronization step in the background reload path, backed by a regression test and documented in a patch release changeset.

Changes

Context Propagation in Background Reloads

Layer / File(s) Summary
Background loader context synchronization
packages/router-core/src/load-matches.ts
In loadRouteMatch's background reload path, syncMatchContext is called immediately after marking the loader as running async, ensuring parent route context is available before the async loader executes.
Context propagation regression test
packages/react-router/tests/routeContext.test.tsx
New test verifies that a route's beforeLoad context value remains available to a sub-route's useRouteContext during background loader execution, through navigation and history.back() scenarios, with assertions that context is never undefined.
Release documentation
.changeset/violet-poets-wait.md
Changeset documents the patch version bump for @tanstack/router-core and records the fix for context propagation during background loader reloads.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Suggested labels

package: router-core, package: react-router

🐰 A context lost in the reloading tide,
Now syncs on time, no more to hide,
Parent whispers, child can hear,
Background loaders, crystal clear! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and concisely describes the main fix: propagating beforeLoad context to a sub-route during background loader reloading, which directly addresses the PR's primary objective.
Linked Issues check ✅ Passed The changes meet the primary objective from issue #7602: context values from beforeLoad are now propagated to sub-routes while their loaders execute in the background, addressing the reported bug.
Out of Scope Changes check ✅ Passed All changes are directly related to fixing the context propagation issue: the core fix in load-matches.ts, the regression test, and the changeset document the fix without introducing unrelated modifications.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ 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 and usage tips.

@nx-cloud

nx-cloud Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

View your CI Pipeline Execution ↗ for commit 92da7bf

Command Status Duration Result
nx affected --targets=test:eslint,test:unit,tes... ✅ Succeeded 11m 13s View ↗
nx run-many --target=build --exclude=examples/*... ✅ Succeeded 2m 19s View ↗

☁️ Nx Cloud last updated this comment at 2026-06-12 22:19:04 UTC

@pkg-pr-new

pkg-pr-new Bot commented Jun 11, 2026

Copy link
Copy Markdown
More templates

@tanstack/arktype-adapter

npm i https://pkg.pr.new/@tanstack/arktype-adapter@7603

@tanstack/eslint-plugin-router

npm i https://pkg.pr.new/@tanstack/eslint-plugin-router@7603

@tanstack/eslint-plugin-start

npm i https://pkg.pr.new/@tanstack/eslint-plugin-start@7603

@tanstack/history

npm i https://pkg.pr.new/@tanstack/history@7603

@tanstack/nitro-v2-vite-plugin

npm i https://pkg.pr.new/@tanstack/nitro-v2-vite-plugin@7603

@tanstack/react-router

npm i https://pkg.pr.new/@tanstack/react-router@7603

@tanstack/react-router-devtools

npm i https://pkg.pr.new/@tanstack/react-router-devtools@7603

@tanstack/react-router-ssr-query

npm i https://pkg.pr.new/@tanstack/react-router-ssr-query@7603

@tanstack/react-start

npm i https://pkg.pr.new/@tanstack/react-start@7603

@tanstack/react-start-client

npm i https://pkg.pr.new/@tanstack/react-start-client@7603

@tanstack/react-start-rsc

npm i https://pkg.pr.new/@tanstack/react-start-rsc@7603

@tanstack/react-start-server

npm i https://pkg.pr.new/@tanstack/react-start-server@7603

@tanstack/router-cli

npm i https://pkg.pr.new/@tanstack/router-cli@7603

@tanstack/router-core

npm i https://pkg.pr.new/@tanstack/router-core@7603

@tanstack/router-devtools

npm i https://pkg.pr.new/@tanstack/router-devtools@7603

@tanstack/router-devtools-core

npm i https://pkg.pr.new/@tanstack/router-devtools-core@7603

@tanstack/router-generator

npm i https://pkg.pr.new/@tanstack/router-generator@7603

@tanstack/router-plugin

npm i https://pkg.pr.new/@tanstack/router-plugin@7603

@tanstack/router-ssr-query-core

npm i https://pkg.pr.new/@tanstack/router-ssr-query-core@7603

@tanstack/router-utils

npm i https://pkg.pr.new/@tanstack/router-utils@7603

@tanstack/router-vite-plugin

npm i https://pkg.pr.new/@tanstack/router-vite-plugin@7603

@tanstack/solid-router

npm i https://pkg.pr.new/@tanstack/solid-router@7603

@tanstack/solid-router-devtools

npm i https://pkg.pr.new/@tanstack/solid-router-devtools@7603

@tanstack/solid-router-ssr-query

npm i https://pkg.pr.new/@tanstack/solid-router-ssr-query@7603

@tanstack/solid-start

npm i https://pkg.pr.new/@tanstack/solid-start@7603

@tanstack/solid-start-client

npm i https://pkg.pr.new/@tanstack/solid-start-client@7603

@tanstack/solid-start-server

npm i https://pkg.pr.new/@tanstack/solid-start-server@7603

@tanstack/start-client-core

npm i https://pkg.pr.new/@tanstack/start-client-core@7603

@tanstack/start-fn-stubs

npm i https://pkg.pr.new/@tanstack/start-fn-stubs@7603

@tanstack/start-plugin-core

npm i https://pkg.pr.new/@tanstack/start-plugin-core@7603

@tanstack/start-server-core

npm i https://pkg.pr.new/@tanstack/start-server-core@7603

@tanstack/start-static-server-functions

npm i https://pkg.pr.new/@tanstack/start-static-server-functions@7603

@tanstack/start-storage-context

npm i https://pkg.pr.new/@tanstack/start-storage-context@7603

@tanstack/valibot-adapter

npm i https://pkg.pr.new/@tanstack/valibot-adapter@7603

@tanstack/virtual-file-routes

npm i https://pkg.pr.new/@tanstack/virtual-file-routes@7603

@tanstack/vue-router

npm i https://pkg.pr.new/@tanstack/vue-router@7603

@tanstack/vue-router-devtools

npm i https://pkg.pr.new/@tanstack/vue-router-devtools@7603

@tanstack/vue-router-ssr-query

npm i https://pkg.pr.new/@tanstack/vue-router-ssr-query@7603

@tanstack/vue-start

npm i https://pkg.pr.new/@tanstack/vue-start@7603

@tanstack/vue-start-client

npm i https://pkg.pr.new/@tanstack/vue-start-client@7603

@tanstack/vue-start-server

npm i https://pkg.pr.new/@tanstack/vue-start-server@7603

@tanstack/zod-adapter

npm i https://pkg.pr.new/@tanstack/zod-adapter@7603

commit: 92da7bf

@codspeed-hq

codspeed-hq Bot commented Jun 11, 2026

Copy link
Copy Markdown

Merging this PR will degrade performance by 3.79%

⚠️ Different runtime environments detected

Some benchmarks with significant performance changes were compared across different runtime environments,
which may affect the accuracy of the results.

Open the report in CodSpeed to investigate

❌ 3 regressed benchmarks
✅ 93 untouched benchmarks

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Mode Benchmark BASE HEAD Efficiency
Simulation client-side navigation loop (react) 55.2 ms 58.1 ms -4.99%
Simulation ssr control-flow unmatched 404 (react) 39.9 ms 41.2 ms -3.31%
Simulation ssr control-flow route headers (react) 25.2 ms 26 ms -3.07%

Tip

Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.


Comparing ulrichstark:fix(router-core)--propagate-beforeLoad-context-to-sub-route-while-its-loader-reloads-in-the-background (92da7bf) with main (a2b9d51)

Open in CodSpeed

@coderabbitai coderabbitai Bot 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: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/react-router/tests/routeContext.test.tsx`:
- Around line 2799-2859: The test currently only asserts the final rendered text
after loader completion, so it doesn't prove context propagation during an
in-flight background reload; change the test (the one named "context value from
beforeLoad..." using contextPropagationRoute, contextPropagationIndexRoute,
beforeLoad, loader and useRouteContext) to assert the route context value while
the second loader run is still pending: make the loader delay (already uses
sleep), start the navigation that triggers the background reload, then assert
immediately (without awaiting loader completion or findByText that waits) that
the component still reads number === 42 (e.g., use a non-awaiting query/get or
waitFor with a short timeout to capture the interim render) before letting the
loader finish so the test verifies context propagation during the in-flight
reload.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 76bc0d76-5649-4338-99ba-29a16650b706

📥 Commits

Reviewing files that changed from the base of the PR and between f04a75c and 92da7bf.

📒 Files selected for processing (1)
  • packages/react-router/tests/routeContext.test.tsx

Comment on lines +2799 to +2859
test('context value from beforeLoad is propagated to a sub-route while its loader reloads in the background', async () => {
let sawUndefinedContext = false

const rootRoute = createRootRoute({
component: () => <Outlet />,
})
const homeRoute = createRoute({
getParentRoute: () => rootRoute,
path: '/',
component: () => <div>Home page</div>,
})
const contextPropagationRoute = createRoute({
getParentRoute: () => rootRoute,
path: '/context-propagation',
beforeLoad: () => ({ number: 42 }),
component: () => <Outlet />,
})
const contextPropagationIndexRoute = createRoute({
getParentRoute: () => contextPropagationRoute,
path: '/',
staleTime: 0,
loader: async () => {
await sleep(WAIT_TIME)
},
component: () => {
const { number } = contextPropagationIndexRoute.useRouteContext()
sawUndefinedContext ||= number === undefined

return (
<div>
number = {String(number)}, saw undefined ={' '}
{String(sawUndefinedContext)}
</div>
)
},
})

const routeTree = rootRoute.addChildren([
homeRoute,
contextPropagationRoute.addChildren([contextPropagationIndexRoute]),
])
const router = createRouter({ routeTree, history })

render(<RouterProvider router={router} />)

await act(() => router.navigate({ to: '/context-propagation' }))

expect(
await screen.findByText('number = 42, saw undefined = false'),
).toBeInTheDocument()

await act(() => router.navigate({ to: '/' }))

expect(await screen.findByText('Home page')).toBeInTheDocument()

act(() => router.history.back())

expect(
await screen.findByText('number = 42, saw undefined = false'),
).toBeInTheDocument()
})

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.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

The regression test does not yet prove the in-flight background reload scenario.

Current checks validate the final state after findByText(...), so this can pass even if render waits for loader completion (or if background reload behavior regresses). The test should assert context while the second loader run is actively pending.

Suggested tightening
 import {
   act,
   cleanup,
   configure,
   fireEvent,
   render,
   screen,
+  waitFor,
 } from '`@testing-library/react`'
@@
   test('context value from beforeLoad is propagated to a sub-route while its loader reloads in the background', async () => {
     let sawUndefinedContext = false
+    let loaderCalls = 0
+    let releaseSecondLoad!: () => void
+    const secondLoadStarted = vi.fn()
+    const secondLoadGate = new Promise<void>((resolve) => {
+      releaseSecondLoad = resolve
+    })
@@
       staleTime: 0,
       loader: async () => {
-        await sleep(WAIT_TIME)
+        loaderCalls += 1
+        if (loaderCalls === 2) {
+          secondLoadStarted()
+          await secondLoadGate
+        }
       },
@@
     act(() => router.history.back())
+    await waitFor(() => expect(secondLoadStarted).toHaveBeenCalledOnce())
 
     expect(
-      await screen.findByText('number = 42, saw undefined = false'),
+      screen.getByText('number = 42, saw undefined = false'),
     ).toBeInTheDocument()
+    releaseSecondLoad()
   })

Based on learnings from the PR objectives and review stack context, this test should explicitly validate context propagation during the background reload window.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/react-router/tests/routeContext.test.tsx` around lines 2799 - 2859,
The test currently only asserts the final rendered text after loader completion,
so it doesn't prove context propagation during an in-flight background reload;
change the test (the one named "context value from beforeLoad..." using
contextPropagationRoute, contextPropagationIndexRoute, beforeLoad, loader and
useRouteContext) to assert the route context value while the second loader run
is still pending: make the loader delay (already uses sleep), start the
navigation that triggers the background reload, then assert immediately (without
awaiting loader completion or findByText that waits) that the component still
reads number === 42 (e.g., use a non-awaiting query/get or waitFor with a short
timeout to capture the interim render) before letting the loader finish so the
test verifies context propagation during the in-flight reload.

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.

Context value coming from beforeLoad isn't propagated to sub-route while loader of sub-route is executing

1 participant