Skip to content

Commit 039889a

Browse files
authored
refactor(router-core): Avoid creating empty objects when not necessary (#4923)
`undefined` is allowed as the parameter of the `...` spread operator. It is not necessary to create an empty object `{}` as a fallback. Creating objects incurs more work by the garbage collector, so minimizing how many are created if a performance improvement.
1 parent 94ea50f commit 039889a

File tree

3 files changed

+48
-45
lines changed

3 files changed

+48
-45
lines changed

packages/router-core/src/Matches.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ export interface RouteMatch<
150150
}
151151
loaderData?: TLoaderData
152152
/** @internal */
153-
__routeContext: Record<string, unknown>
153+
__routeContext?: Record<string, unknown>
154154
/** @internal */
155155
__beforeLoadContext?: Record<string, unknown>
156156
context: TAllContext

packages/router-core/src/router.ts

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1146,8 +1146,8 @@ export class RouterCore<
11461146
const parentMatchId = parentMatch?.id
11471147

11481148
const parentContext = !parentMatchId
1149-
? ((this.options.context as any) ?? {})
1150-
: (parentMatch.context ?? this.options.context ?? {})
1149+
? ((this.options.context as any) ?? undefined)
1150+
: (parentMatch.context ?? this.options.context ?? undefined)
11511151

11521152
return parentContext
11531153
}
@@ -1169,12 +1169,12 @@ export class RouterCore<
11691169
] = (() => {
11701170
// Validate the search params and stabilize them
11711171
const parentSearch = parentMatch?.search ?? next.search
1172-
const parentStrictSearch = parentMatch?._strictSearch ?? {}
1172+
const parentStrictSearch = parentMatch?._strictSearch ?? undefined
11731173

11741174
try {
11751175
const strictSearch =
11761176
validateSearch(route.options.validateSearch, { ...parentSearch }) ??
1177-
{}
1177+
undefined
11781178

11791179
return [
11801180
{
@@ -1284,7 +1284,7 @@ export class RouterCore<
12841284
isFetching: false,
12851285
error: undefined,
12861286
paramsError: parseErrors[index],
1287-
__routeContext: {},
1287+
__routeContext: undefined,
12881288
_nonReactive: {
12891289
loadPromise: createControlledPromise(),
12901290
},
@@ -1337,22 +1337,25 @@ export class RouterCore<
13371337
const parentContext = getParentContext(parentMatch)
13381338

13391339
// Update the match's context
1340-
const contextFnContext: RouteContextOptions<any, any, any, any> = {
1341-
deps: match.loaderDeps,
1342-
params: match.params,
1343-
context: parentContext,
1344-
location: next,
1345-
navigate: (opts: any) =>
1346-
this.navigate({ ...opts, _fromLocation: next }),
1347-
buildLocation: this.buildLocation,
1348-
cause: match.cause,
1349-
abortController: match.abortController,
1350-
preload: !!match.preload,
1351-
matches,
1352-
}
13531340

1354-
// Get the route context
1355-
match.__routeContext = route.options.context?.(contextFnContext) ?? {}
1341+
if (route.options.context) {
1342+
const contextFnContext: RouteContextOptions<any, any, any, any> = {
1343+
deps: match.loaderDeps,
1344+
params: match.params,
1345+
context: parentContext ?? {},
1346+
location: next,
1347+
navigate: (opts: any) =>
1348+
this.navigate({ ...opts, _fromLocation: next }),
1349+
buildLocation: this.buildLocation,
1350+
cause: match.cause,
1351+
abortController: match.abortController,
1352+
preload: !!match.preload,
1353+
matches,
1354+
}
1355+
// Get the route context
1356+
match.__routeContext =
1357+
route.options.context(contextFnContext) ?? undefined
1358+
}
13561359

13571360
match.context = {
13581361
...parentContext,
@@ -1486,13 +1489,9 @@ export class RouterCore<
14861489
parseCache: this.parsePathnameCache,
14871490
}).interpolatedPath
14881491

1489-
const destRoutes = this.matchRoutes(
1490-
interpolatedNextTo,
1491-
{},
1492-
{
1493-
_buildLocation: true,
1494-
},
1495-
).map((d) => this.looseRoutesById[d.routeId]!)
1492+
const destRoutes = this.matchRoutes(interpolatedNextTo, undefined, {
1493+
_buildLocation: true,
1494+
}).map((d) => this.looseRoutesById[d.routeId]!)
14961495

14971496
// If there are any params, we need to stringify them
14981497
if (Object.keys(nextParams).length > 0) {
@@ -2378,7 +2377,7 @@ export class RouterCore<
23782377
const abortController = new AbortController()
23792378

23802379
const parentMatchContext =
2381-
parentMatch?.context ?? this.options.context ?? {}
2380+
parentMatch?.context ?? this.options.context ?? undefined
23822381

23832382
updateMatch(matchId, (prev) => ({
23842383
...prev,
@@ -2787,7 +2786,7 @@ export class RouterCore<
27872786
invalid: true,
27882787
...(opts?.forcePending || d.status === 'error'
27892788
? ({ status: 'pending', error: undefined } as const)
2790-
: {}),
2789+
: undefined),
27912790
}
27922791
}
27932792
return d
@@ -3558,7 +3557,8 @@ function applySearchMiddleware({
35583557
try {
35593558
const validatedSearch = {
35603559
...result,
3561-
...(validateSearch(route.options.validateSearch, result) ?? {}),
3560+
...(validateSearch(route.options.validateSearch, result) ??
3561+
undefined),
35623562
}
35633563
return validatedSearch
35643564
} catch {

packages/router-core/src/ssr/ssr-client.ts

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -139,24 +139,27 @@ export async function hydrate(router: AnyRouter): Promise<any> {
139139
const route = router.looseRoutesById[match.routeId]!
140140

141141
const parentMatch = router.state.matches[match.index - 1]
142-
const parentContext = parentMatch?.context ?? router.options.context ?? {}
142+
const parentContext = parentMatch?.context ?? router.options.context
143143

144144
// `context()` was already executed by `matchRoutes`, however route context was not yet fully reconstructed
145145
// so run it again and merge route context
146-
const contextFnContext: RouteContextOptions<any, any, any, any> = {
147-
deps: match.loaderDeps,
148-
params: match.params,
149-
context: parentContext,
150-
location: router.state.location,
151-
navigate: (opts: any) =>
152-
router.navigate({ ...opts, _fromLocation: router.state.location }),
153-
buildLocation: router.buildLocation,
154-
cause: match.cause,
155-
abortController: match.abortController,
156-
preload: false,
157-
matches,
146+
if (route.options.context) {
147+
const contextFnContext: RouteContextOptions<any, any, any, any> = {
148+
deps: match.loaderDeps,
149+
params: match.params,
150+
context: parentContext ?? {},
151+
location: router.state.location,
152+
navigate: (opts: any) =>
153+
router.navigate({ ...opts, _fromLocation: router.state.location }),
154+
buildLocation: router.buildLocation,
155+
cause: match.cause,
156+
abortController: match.abortController,
157+
preload: false,
158+
matches,
159+
}
160+
match.__routeContext =
161+
route.options.context(contextFnContext) ?? undefined
158162
}
159-
match.__routeContext = route.options.context?.(contextFnContext) ?? {}
160163

161164
match.context = {
162165
...parentContext,

0 commit comments

Comments
 (0)