@tanstack/react-router 0.0.1-beta.225 → 0.0.1-beta.227
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/cjs/Matches.js +8 -6
- package/build/cjs/Matches.js.map +1 -1
- package/build/cjs/RouterProvider.js +1 -26
- package/build/cjs/RouterProvider.js.map +1 -1
- package/build/cjs/fileRoute.js.map +1 -1
- package/build/cjs/route.js.map +1 -1
- package/build/cjs/router.js +54 -54
- package/build/cjs/router.js.map +1 -1
- package/build/esm/index.js +62 -86
- package/build/esm/index.js.map +1 -1
- package/build/stats-html.html +1 -1
- package/build/stats-react.json +291 -285
- package/build/types/Matches.d.ts +0 -1
- package/build/types/RouterProvider.d.ts +1 -6
- package/build/types/fileRoute.d.ts +2 -2
- package/build/types/route.d.ts +7 -3
- package/build/types/router.d.ts +7 -3
- package/build/umd/index.development.js +62 -86
- package/build/umd/index.development.js.map +1 -1
- package/build/umd/index.production.js +1 -1
- package/build/umd/index.production.js.map +1 -1
- package/package.json +2 -2
- package/src/Matches.tsx +21 -23
- package/src/RouterProvider.tsx +10 -79
- package/src/fileRoute.ts +7 -6
- package/src/route.ts +39 -39
- package/src/router.ts +95 -88
package/src/router.ts
CHANGED
|
@@ -43,7 +43,6 @@ import {
|
|
|
43
43
|
BuildLocationFn,
|
|
44
44
|
CommitLocationOptions,
|
|
45
45
|
InjectedHtmlEntry,
|
|
46
|
-
LoadFn,
|
|
47
46
|
MatchRouteFn,
|
|
48
47
|
NavigateFn,
|
|
49
48
|
PathParamError,
|
|
@@ -554,67 +553,21 @@ export class Router<
|
|
|
554
553
|
return
|
|
555
554
|
})
|
|
556
555
|
|
|
557
|
-
const matches =
|
|
558
|
-
const interpolatedPath = interpolatePath(route.path, routeParams)
|
|
559
|
-
const matchId = interpolatePath(route.id, routeParams, true)
|
|
560
|
-
|
|
561
|
-
// Waste not, want not. If we already have a match for this route,
|
|
562
|
-
// reuse it. This is important for layout routes, which might stick
|
|
563
|
-
// around between navigation actions that only change leaf routes.
|
|
564
|
-
const existingMatch = getRouteMatch(this.state, matchId)
|
|
565
|
-
|
|
566
|
-
const cause = this.state.matches.find((d) => d.id === matchId)
|
|
567
|
-
? 'stay'
|
|
568
|
-
: 'enter'
|
|
569
|
-
|
|
570
|
-
if (existingMatch) {
|
|
571
|
-
return { ...existingMatch, cause }
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
// Create a fresh route match
|
|
575
|
-
const hasLoaders = !!(
|
|
576
|
-
route.options.loader ||
|
|
577
|
-
componentTypes.some((d) => (route.options[d] as any)?.preload)
|
|
578
|
-
)
|
|
556
|
+
const matches: AnyRouteMatch[] = []
|
|
579
557
|
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
search: {} as any,
|
|
588
|
-
status: hasLoaders ? 'pending' : 'success',
|
|
589
|
-
isFetching: false,
|
|
590
|
-
invalid: false,
|
|
591
|
-
error: undefined,
|
|
592
|
-
paramsError: parseErrors[index],
|
|
593
|
-
searchError: undefined,
|
|
594
|
-
loadPromise: Promise.resolve(),
|
|
595
|
-
context: undefined!,
|
|
596
|
-
abortController: new AbortController(),
|
|
597
|
-
shouldReloadDeps: undefined,
|
|
598
|
-
fetchedAt: 0,
|
|
599
|
-
cause,
|
|
600
|
-
}
|
|
558
|
+
matchedRoutes.forEach((route, index) => {
|
|
559
|
+
// Take each matched route and resolve + validate its search params
|
|
560
|
+
// This has to happen serially because each route's search params
|
|
561
|
+
// can depend on the parent route's search params
|
|
562
|
+
// It must also happen before we create the match so that we can
|
|
563
|
+
// pass the search params to the route's potential key function
|
|
564
|
+
// which is used to uniquely identify the route match in state
|
|
601
565
|
|
|
602
|
-
|
|
603
|
-
})
|
|
566
|
+
const parentMatch = matches[index - 1]
|
|
604
567
|
|
|
605
|
-
|
|
606
|
-
// This has to happen after the matches are created or found
|
|
607
|
-
// so that we can use the parent match's search params and context
|
|
608
|
-
matches.forEach((match, i): any => {
|
|
609
|
-
const parentMatch = matches[i - 1]
|
|
610
|
-
const route = this.looseRoutesById[match.routeId]!
|
|
611
|
-
|
|
612
|
-
const searchInfo = (() => {
|
|
568
|
+
const [preMatchSearch, searchError]: [Record<string, any>, any] = (() => {
|
|
613
569
|
// Validate the search params and stabilize them
|
|
614
|
-
const
|
|
615
|
-
search: parentMatch?.search ?? locationSearch,
|
|
616
|
-
routeSearch: parentMatch?.routeSearch ?? locationSearch,
|
|
617
|
-
}
|
|
570
|
+
const parentSearch = parentMatch?.search ?? locationSearch
|
|
618
571
|
|
|
619
572
|
try {
|
|
620
573
|
const validator =
|
|
@@ -622,35 +575,81 @@ export class Router<
|
|
|
622
575
|
? route.options.validateSearch.parse
|
|
623
576
|
: route.options.validateSearch
|
|
624
577
|
|
|
625
|
-
let
|
|
626
|
-
|
|
627
|
-
let search = {
|
|
628
|
-
...parentSearchInfo.search,
|
|
629
|
-
...routeSearch,
|
|
630
|
-
}
|
|
631
|
-
|
|
632
|
-
routeSearch = replaceEqualDeep(match.routeSearch, routeSearch)
|
|
633
|
-
search = replaceEqualDeep(match.search, search)
|
|
578
|
+
let search = validator?.(parentSearch) ?? {}
|
|
634
579
|
|
|
635
|
-
return
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
580
|
+
return [
|
|
581
|
+
{
|
|
582
|
+
...parentSearch,
|
|
583
|
+
...search,
|
|
584
|
+
},
|
|
585
|
+
undefined,
|
|
586
|
+
]
|
|
640
587
|
} catch (err: any) {
|
|
641
|
-
|
|
588
|
+
const searchError = new SearchParamError(err.message, {
|
|
642
589
|
cause: err,
|
|
643
590
|
})
|
|
644
591
|
|
|
645
592
|
if (opts?.throwOnError) {
|
|
646
|
-
throw
|
|
593
|
+
throw searchError
|
|
647
594
|
}
|
|
648
595
|
|
|
649
|
-
return
|
|
596
|
+
return [parentSearch, searchError]
|
|
650
597
|
}
|
|
651
598
|
})()
|
|
652
599
|
|
|
653
|
-
|
|
600
|
+
const interpolatedPath = interpolatePath(route.path, routeParams)
|
|
601
|
+
const matchId =
|
|
602
|
+
interpolatePath(route.id, routeParams, true) +
|
|
603
|
+
(route.options.key?.({
|
|
604
|
+
search: preMatchSearch,
|
|
605
|
+
location: this.state.location,
|
|
606
|
+
}) ?? '')
|
|
607
|
+
|
|
608
|
+
// Waste not, want not. If we already have a match for this route,
|
|
609
|
+
// reuse it. This is important for layout routes, which might stick
|
|
610
|
+
// around between navigation actions that only change leaf routes.
|
|
611
|
+
const existingMatch = getRouteMatch(this.state, matchId)
|
|
612
|
+
|
|
613
|
+
const cause = this.state.matches.find((d) => d.id === matchId)
|
|
614
|
+
? 'stay'
|
|
615
|
+
: 'enter'
|
|
616
|
+
|
|
617
|
+
// Create a fresh route match
|
|
618
|
+
const hasLoaders = !!(
|
|
619
|
+
route.options.loader ||
|
|
620
|
+
componentTypes.some((d) => (route.options[d] as any)?.preload)
|
|
621
|
+
)
|
|
622
|
+
|
|
623
|
+
const match: AnyRouteMatch = existingMatch
|
|
624
|
+
? { ...existingMatch, cause }
|
|
625
|
+
: {
|
|
626
|
+
id: matchId,
|
|
627
|
+
routeId: route.id,
|
|
628
|
+
params: routeParams,
|
|
629
|
+
pathname: joinPaths([this.basepath, interpolatedPath]),
|
|
630
|
+
updatedAt: Date.now(),
|
|
631
|
+
search: {} as any,
|
|
632
|
+
searchError: undefined,
|
|
633
|
+
status: hasLoaders ? 'pending' : 'success',
|
|
634
|
+
isFetching: false,
|
|
635
|
+
invalid: false,
|
|
636
|
+
error: undefined,
|
|
637
|
+
paramsError: parseErrors[index],
|
|
638
|
+
loadPromise: Promise.resolve(),
|
|
639
|
+
context: undefined!,
|
|
640
|
+
abortController: new AbortController(),
|
|
641
|
+
shouldReloadDeps: undefined,
|
|
642
|
+
fetchedAt: 0,
|
|
643
|
+
cause,
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
// Regardless of whether we're reusing an existing match or creating
|
|
647
|
+
// a new one, we need to update the match's search params
|
|
648
|
+
match.search = replaceEqualDeep(match.search, preMatchSearch)
|
|
649
|
+
// And also update the searchError if there is one
|
|
650
|
+
match.searchError = searchError
|
|
651
|
+
|
|
652
|
+
matches.push(match)
|
|
654
653
|
})
|
|
655
654
|
|
|
656
655
|
return matches as any
|
|
@@ -679,8 +678,8 @@ export class Router<
|
|
|
679
678
|
let pathname = this.resolvePathWithBase(fromPathname, `${dest.to ?? ''}`)
|
|
680
679
|
|
|
681
680
|
const fromMatches = this.matchRoutes(fromPathname, from.search)
|
|
682
|
-
const stayingMatches = matches?.filter(
|
|
683
|
-
fromMatches?.find((e) => e.routeId === d.routeId),
|
|
681
|
+
const stayingMatches = matches?.filter(
|
|
682
|
+
(d) => fromMatches?.find((e) => e.routeId === d.routeId),
|
|
684
683
|
)
|
|
685
684
|
|
|
686
685
|
const prevParams = { ...last(fromMatches)?.params }
|
|
@@ -734,10 +733,10 @@ export class Router<
|
|
|
734
733
|
dest.search === true
|
|
735
734
|
? preFilteredSearch // Preserve resolvedFrom true
|
|
736
735
|
: dest.search
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
736
|
+
? functionalUpdate(dest.search, preFilteredSearch) ?? {} // Updater
|
|
737
|
+
: preSearchFilters?.length
|
|
738
|
+
? preFilteredSearch // Preserve resolvedFrom filters
|
|
739
|
+
: {}
|
|
741
740
|
|
|
742
741
|
// Then post filters
|
|
743
742
|
const postFilteredSearch = postSearchFilters?.length
|
|
@@ -752,8 +751,8 @@ export class Router<
|
|
|
752
751
|
dest.hash === true
|
|
753
752
|
? from.hash
|
|
754
753
|
: dest.hash
|
|
755
|
-
|
|
756
|
-
|
|
754
|
+
? functionalUpdate(dest.hash!, from.hash)
|
|
755
|
+
: from.hash
|
|
757
756
|
|
|
758
757
|
const hashStr = hash ? `#${hash}` : ''
|
|
759
758
|
|
|
@@ -761,8 +760,8 @@ export class Router<
|
|
|
761
760
|
dest.state === true
|
|
762
761
|
? from.state
|
|
763
762
|
: dest.state
|
|
764
|
-
|
|
765
|
-
|
|
763
|
+
? functionalUpdate(dest.state, from.state)
|
|
764
|
+
: from.state
|
|
766
765
|
|
|
767
766
|
nextState = replaceEqualDeep(from.state, nextState)
|
|
768
767
|
|
|
@@ -945,10 +944,12 @@ export class Router<
|
|
|
945
944
|
checkLatest,
|
|
946
945
|
matches,
|
|
947
946
|
preload,
|
|
947
|
+
invalidate,
|
|
948
948
|
}: {
|
|
949
949
|
checkLatest: () => Promise<void> | undefined
|
|
950
950
|
matches: AnyRouteMatch[]
|
|
951
951
|
preload?: boolean
|
|
952
|
+
invalidate?: boolean
|
|
952
953
|
}): Promise<RouteMatch[]> => {
|
|
953
954
|
let latestPromise
|
|
954
955
|
let firstBadMatchIndex: number | undefined
|
|
@@ -1086,7 +1087,7 @@ export class Router<
|
|
|
1086
1087
|
? route.options.shouldReload?.(loaderContext)
|
|
1087
1088
|
: !!(route.options.shouldReload ?? true)
|
|
1088
1089
|
|
|
1089
|
-
if (match.cause === 'enter') {
|
|
1090
|
+
if (match.cause === 'enter' || invalidate) {
|
|
1090
1091
|
match.shouldReloadDeps = shouldReloadDeps
|
|
1091
1092
|
} else if (match.cause === 'stay') {
|
|
1092
1093
|
if (typeof shouldReloadDeps === 'object') {
|
|
@@ -1192,7 +1193,12 @@ export class Router<
|
|
|
1192
1193
|
return matches
|
|
1193
1194
|
}
|
|
1194
1195
|
|
|
1195
|
-
|
|
1196
|
+
invalidate = () =>
|
|
1197
|
+
this.load({
|
|
1198
|
+
invalidate: true,
|
|
1199
|
+
})
|
|
1200
|
+
|
|
1201
|
+
load = async (opts?: { invalidate?: boolean }): Promise<void> => {
|
|
1196
1202
|
const promise = new Promise<void>(async (resolve, reject) => {
|
|
1197
1203
|
const next = this.latestLocation
|
|
1198
1204
|
const prevLocation = this.state.resolvedLocation
|
|
@@ -1236,6 +1242,7 @@ export class Router<
|
|
|
1236
1242
|
await this.loadMatches({
|
|
1237
1243
|
matches,
|
|
1238
1244
|
checkLatest: () => this.checkLatest(promise),
|
|
1245
|
+
invalidate: opts?.invalidate,
|
|
1239
1246
|
})
|
|
1240
1247
|
} catch (err) {
|
|
1241
1248
|
// swallow this error, since we'll display the
|