Skip to content

Commit e6aef99

Browse files
committed
feat: provide location in onEnter/onStay/onLeave hooks
1 parent a119869 commit e6aef99

File tree

7 files changed

+57
-12
lines changed

7 files changed

+57
-12
lines changed

docs/router/framework/react/api/router/RouteOptionsType.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -245,19 +245,19 @@ type loaderDeps = (opts: { search: TFullSearchSchema }) => Record<string, any>
245245
246246
### `onEnter` property
247247
248-
- Type: `(match: RouteMatch) => void`
248+
- Type: `(match: RouteMatch, { location }: { location: ParsedLocation<{}> }) => void`
249249
- Optional
250250
- A function that will be called when a route is matched and loaded after not being matched in the previous location.
251251
252252
### `onStay` property
253253
254-
- Type: `(match: RouteMatch) => void`
254+
- Type: `(match: RouteMatch, { location }: { location: ParsedLocation<{}> }) => void`
255255
- Optional
256256
- A function that will be called when a route is matched and loaded after being matched in the previous location.
257257
258258
### `onLeave` property
259259
260-
- Type: `(match: RouteMatch) => void`
260+
- Type: `(match: RouteMatch, { location }: { location: ParsedLocation<{}> }) => void`
261261
- Optional
262262
- A function that will be called when a route is no longer matched after being matched in the previous location.
263263

examples/react/basic/src/main.tsx

+18
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,15 @@ import type { ErrorComponentProps } from '@tanstack/react-router'
1414
import './styles.css'
1515

1616
const rootRoute = createRootRoute({
17+
onEnter: (match, { location }) => {
18+
console.log('Entering root route', match, location.pathname)
19+
},
20+
onStay: (match, { location }) => {
21+
console.log('Staying root route', match, location.pathname)
22+
},
23+
onLeave: (match, { location }) => {
24+
console.log('Leaving root route', match, location.pathname)
25+
},
1726
component: RootComponent,
1827
notFoundComponent: () => {
1928
return (
@@ -190,6 +199,15 @@ function PathlessLayoutAComponent() {
190199
}
191200

192201
const pathlessLayoutBRoute = createRoute({
202+
onEnter: (match, { location }) => {
203+
console.log('Entering route-b route', match, location.pathname)
204+
},
205+
onStay: (match, { location }) => {
206+
console.log('Staying route-b route', match, location.pathname)
207+
},
208+
onLeave: (match, { location }) => {
209+
console.log('Leaving route-b route', match, location.pathname)
210+
},
193211
getParentRoute: () => nestedPathlessLayout2Route,
194212
path: '/route-b',
195213
component: PathlessLayoutBComponent,

packages/react-router/src/router.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -2003,7 +2003,10 @@ export class Router<
20032003
] as const
20042004
).forEach(([matches, hook]) => {
20052005
matches.forEach((match) => {
2006-
this.looseRoutesById[match.routeId]!.options[hook]?.(match)
2006+
this.looseRoutesById[match.routeId]!.options[hook]?.(
2007+
match,
2008+
{ location: next },
2009+
)
20072010
})
20082011
})
20092012
})

packages/react-router/tests/route.test-d.tsx

+12-3
Original file line numberDiff line numberDiff line change
@@ -1321,9 +1321,18 @@ test('when creating a child route with context, search, params, loader, loaderDe
13211321
invoicePage: deps.search.page,
13221322
}),
13231323
loader: () => ({ detailLoader: 'detailResult' }) as const,
1324-
onEnter: (match) => expectTypeOf(match).toMatchTypeOf<TExpectedMatch>(),
1325-
onStay: (match) => expectTypeOf(match).toMatchTypeOf<TExpectedMatch>(),
1326-
onLeave: (match) => expectTypeOf(match).toMatchTypeOf<TExpectedMatch>(),
1324+
onEnter: (match, { location }) => {
1325+
expectTypeOf(match).toMatchTypeOf<TExpectedMatch>()
1326+
expectTypeOf(location).toMatchTypeOf<ParsedLocation<{}>>()
1327+
},
1328+
onStay: (match, { location }) => {
1329+
expectTypeOf(match).toMatchTypeOf<TExpectedMatch>()
1330+
expectTypeOf(location).toMatchTypeOf<ParsedLocation<{}>>()
1331+
},
1332+
onLeave: (match, { location }) => {
1333+
expectTypeOf(match).toMatchTypeOf<TExpectedMatch>()
1334+
expectTypeOf(location).toMatchTypeOf<ParsedLocation<{}>>()
1335+
},
13271336
})
13281337
})
13291338

packages/router-core/src/route.ts

+3
Original file line numberDiff line numberDiff line change
@@ -865,6 +865,7 @@ export interface UpdatableRouteOptions<
865865
>,
866866
TLoaderDeps
867867
>,
868+
{ location }: { location: ParsedLocation<{}> },
868869
) => void
869870
onStay?: (
870871
match: RouteMatch<
@@ -881,6 +882,7 @@ export interface UpdatableRouteOptions<
881882
>,
882883
TLoaderDeps
883884
>,
885+
{ location }: { location: ParsedLocation<{}> },
884886
) => void
885887
onLeave?: (
886888
match: RouteMatch<
@@ -897,6 +899,7 @@ export interface UpdatableRouteOptions<
897899
>,
898900
TLoaderDeps
899901
>,
902+
{ location }: { location: ParsedLocation<{}> },
900903
) => void
901904
headers?: (ctx: {
902905
loaderData: ResolveLoaderData<TLoaderFn>

packages/solid-router/src/router.ts

+5-2
Original file line numberDiff line numberDiff line change
@@ -791,7 +791,7 @@ export class Router<
791791
if (
792792
typeof window !== 'undefined' &&
793793
'CSS' in window &&
794-
typeof window.CSS?.supports === 'function'
794+
typeof window.CSS.supports === 'function'
795795
) {
796796
this.isViewTransitionTypesSupported = window.CSS.supports(
797797
'selector(:active-view-transition-type(a)',
@@ -1977,7 +1977,10 @@ export class Router<
19771977
] as const
19781978
).forEach(([matches, hook]) => {
19791979
matches.forEach((match) => {
1980-
this.looseRoutesById[match.routeId]!.options[hook]?.(match)
1980+
this.looseRoutesById[match.routeId]!.options[hook]?.(
1981+
match,
1982+
{ location: next },
1983+
)
19811984
})
19821985
})
19831986
})

packages/solid-router/tests/route.test-d.tsx

+12-3
Original file line numberDiff line numberDiff line change
@@ -1286,9 +1286,18 @@ test('when creating a child route with context, search, params, loader, loaderDe
12861286
invoicePage: deps.search.page,
12871287
}),
12881288
loader: () => ({ detailLoader: 'detailResult' }) as const,
1289-
onEnter: (match) => expectTypeOf(match).toMatchTypeOf<TExpectedMatch>(),
1290-
onStay: (match) => expectTypeOf(match).toMatchTypeOf<TExpectedMatch>(),
1291-
onLeave: (match) => expectTypeOf(match).toMatchTypeOf<TExpectedMatch>(),
1289+
onEnter: (match, { location }) => {
1290+
expectTypeOf(match).toMatchTypeOf<TExpectedMatch>()
1291+
expectTypeOf(location).toMatchTypeOf<ParsedLocation<{}>>()
1292+
},
1293+
onStay: (match, { location }) => {
1294+
expectTypeOf(match).toMatchTypeOf<TExpectedMatch>()
1295+
expectTypeOf(location).toMatchTypeOf<ParsedLocation<{}>>()
1296+
},
1297+
onLeave: (match, { location }) => {
1298+
expectTypeOf(match).toMatchTypeOf<TExpectedMatch>()
1299+
expectTypeOf(location).toMatchTypeOf<ParsedLocation<{}>>()
1300+
},
12921301
})
12931302
})
12941303

0 commit comments

Comments
 (0)