diff --git a/.changeset/violet-poets-wait.md b/.changeset/violet-poets-wait.md new file mode 100644 index 0000000000..8d86936fec --- /dev/null +++ b/.changeset/violet-poets-wait.md @@ -0,0 +1,5 @@ +--- +'@tanstack/router-core': patch +--- + +Fix context value from a parent route's `beforeLoad` not being propagated to a sub-route while the sub-route's loader is reloading in the background diff --git a/packages/react-router/tests/routeContext.test.tsx b/packages/react-router/tests/routeContext.test.tsx index d11f86420e..b92f0c374f 100644 --- a/packages/react-router/tests/routeContext.test.tsx +++ b/packages/react-router/tests/routeContext.test.tsx @@ -2796,6 +2796,68 @@ describe('useRouteContext in the component', () => { expect(content).toBeInTheDocument() }) + 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: () => , + }) + const homeRoute = createRoute({ + getParentRoute: () => rootRoute, + path: '/', + component: () =>
Home page
, + }) + const contextPropagationRoute = createRoute({ + getParentRoute: () => rootRoute, + path: '/context-propagation', + beforeLoad: () => ({ number: 42 }), + component: () => , + }) + const contextPropagationIndexRoute = createRoute({ + getParentRoute: () => contextPropagationRoute, + path: '/', + staleTime: 0, + loader: async () => { + await sleep(WAIT_TIME) + }, + component: () => { + const { number } = contextPropagationIndexRoute.useRouteContext() + sawUndefinedContext ||= number === undefined + + return ( +
+ number = {String(number)}, saw undefined ={' '} + {String(sawUndefinedContext)} +
+ ) + }, + }) + + const routeTree = rootRoute.addChildren([ + homeRoute, + contextPropagationRoute.addChildren([contextPropagationIndexRoute]), + ]) + const router = createRouter({ routeTree, history }) + + render() + + 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() + }) + // Check if context that is updated at the root, is the same in the root route test('modified route context, present in the root route', async () => { const rootRoute = createRootRoute({ diff --git a/packages/router-core/src/load-matches.ts b/packages/router-core/src/load-matches.ts index f901a0c97d..20d31afd1d 100644 --- a/packages/router-core/src/load-matches.ts +++ b/packages/router-core/src/load-matches.ts @@ -832,6 +832,7 @@ const loadRouteMatch = async ( shouldReloadInBackground ) { loaderIsRunningAsync = true + syncMatchContext(inner, matchId, index) ;(async () => { try { await runLoader(inner, matchPromises, matchId, index, route)