Skip to content

Commit e854fd7

Browse files
committed
fix: route context being undefined when navigating to a new route faster than beforeLoad resolves
1 parent 98dc050 commit e854fd7

File tree

2 files changed

+115
-0
lines changed

2 files changed

+115
-0
lines changed

packages/react-router/tests/routeContext.test.tsx

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'
1010
import { z } from 'zod'
1111

12+
import { useEffect } from 'react'
1213
import {
1314
Link,
1415
Outlet,
@@ -2475,6 +2476,61 @@ describe('useRouteContext in the component', () => {
24752476
expect(content).toBeInTheDocument()
24762477
})
24772478

2479+
test('route context, (sleep in beforeLoad), with immediate navigation', async () => {
2480+
const contextValues: Array<{ data: string }> = []
2481+
2482+
const rootRoute = createRootRoute({
2483+
beforeLoad: async () => {
2484+
await sleep(WAIT_TIME)
2485+
return { data: 'context-from-beforeLoad' }
2486+
},
2487+
component: () => {
2488+
const context: { data: string } = rootRoute.useRouteContext()
2489+
2490+
// Track all context values we receive
2491+
contextValues.push(context)
2492+
2493+
return <Outlet />
2494+
},
2495+
})
2496+
2497+
function Component() {
2498+
const navigate = indexRoute.useNavigate()
2499+
2500+
// Navigate away immediately on mount
2501+
useEffect(() => {
2502+
navigate({ to: '/other' })
2503+
}, [navigate])
2504+
2505+
return <div>Index page</div>
2506+
}
2507+
2508+
const indexRoute = createRoute({
2509+
getParentRoute: () => rootRoute,
2510+
path: '/',
2511+
component: Component,
2512+
})
2513+
2514+
const otherRoute = createRoute({
2515+
getParentRoute: () => rootRoute,
2516+
path: '/other',
2517+
component: () => <div>Other page</div>,
2518+
})
2519+
2520+
const routeTree = rootRoute.addChildren([indexRoute, otherRoute])
2521+
const router = createRouter({ routeTree, history })
2522+
2523+
render(<RouterProvider router={router} />)
2524+
2525+
// Wait for navigation to complete
2526+
await screen.findByText('Other page')
2527+
2528+
const allContextsValid = contextValues.every(
2529+
(c) => c.data === 'context-from-beforeLoad',
2530+
)
2531+
expect(allContextsValid).toBe(true)
2532+
})
2533+
24782534
test('route context (sleep in loader), present in the index route', async () => {
24792535
const rootRoute = createRootRoute({})
24802536
const indexRoute = createRoute({

packages/solid-router/tests/routeContext.test.tsx

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { cleanup, fireEvent, render, screen } from '@solidjs/testing-library'
22
import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'
33
import { z } from 'zod'
44

5+
import { createEffect, onMount } from 'solid-js'
56
import {
67
Link,
78
Outlet,
@@ -2392,6 +2393,64 @@ describe('useRouteContext in the component', () => {
23922393
expect(content).toBeInTheDocument()
23932394
})
23942395

2396+
// Note: This test passes in solid-router but fails in react-router, even
2397+
// though in issue (GitHub #6040), the bug manifests in both routers.
2398+
test('route context, (sleep in beforeLoad), with immediate navigation', async () => {
2399+
const contextValues: Array<{ data: string }> = []
2400+
2401+
const rootRoute = createRootRoute({
2402+
beforeLoad: async () => {
2403+
await sleep(WAIT_TIME)
2404+
return { data: 'context-from-beforeLoad' }
2405+
},
2406+
shellComponent: () => {
2407+
const context = rootRoute.useRouteContext()
2408+
2409+
// Track context value at render time
2410+
createEffect(() => {
2411+
const contextValue: { data: string } = context()
2412+
contextValues.push(contextValue)
2413+
})
2414+
2415+
return <Outlet />
2416+
},
2417+
})
2418+
2419+
const indexRoute = createRoute({
2420+
getParentRoute: () => rootRoute,
2421+
path: '/',
2422+
component: () => {
2423+
const navigate = indexRoute.useNavigate()
2424+
2425+
// Navigate away immediately on mount
2426+
onMount(() => {
2427+
navigate({ to: '/other' })
2428+
})
2429+
2430+
return <div>Index page</div>
2431+
},
2432+
})
2433+
2434+
const otherRoute = createRoute({
2435+
getParentRoute: () => rootRoute,
2436+
path: '/other',
2437+
component: () => <div>Other page</div>,
2438+
})
2439+
2440+
const routeTree = rootRoute.addChildren([indexRoute, otherRoute])
2441+
const router = createRouter({ routeTree, history })
2442+
2443+
render(() => <RouterProvider router={router} />)
2444+
2445+
// Wait for navigation to complete
2446+
await screen.findByText('Other page')
2447+
2448+
const allContextsValid = contextValues.every(
2449+
(c) => c.data === 'context-from-beforeLoad',
2450+
)
2451+
expect(allContextsValid).toBe(true)
2452+
})
2453+
23952454
test('route context (sleep in loader), present root route', async () => {
23962455
const rootRoute = createRootRoute({
23972456
loader: async () => {

0 commit comments

Comments
 (0)