@tanstack/react-router 0.0.1-beta.273 → 0.0.1-beta.274
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.map +1 -1
- package/build/cjs/RouterProvider.js +9 -6
- package/build/cjs/RouterProvider.js.map +1 -1
- package/build/cjs/index.js +4 -1
- package/build/cjs/index.js.map +1 -1
- package/build/cjs/route.js.map +1 -1
- package/build/cjs/router.js +150 -100
- package/build/cjs/router.js.map +1 -1
- package/build/esm/index.js +157 -103
- package/build/esm/index.js.map +1 -1
- package/build/stats-html.html +1 -1
- package/build/stats-react.json +353 -353
- package/build/types/Matches.d.ts +2 -2
- package/build/types/RouterProvider.d.ts +1 -1
- package/build/types/route.d.ts +2 -2
- package/build/types/router.d.ts +3 -1
- package/build/umd/index.development.js +159 -106
- 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 +2 -2
- package/src/RouterProvider.tsx +11 -5
- package/src/route.ts +2 -2
- package/src/router.ts +197 -128
package/build/types/Matches.d.ts
CHANGED
|
@@ -22,10 +22,10 @@ export interface RouteMatch<TRouteTree extends AnyRoute = AnyRoute, TRouteId ext
|
|
|
22
22
|
routeContext: RouteById<TRouteTree, TRouteId>['types']['routeContext'];
|
|
23
23
|
context: RouteById<TRouteTree, TRouteId>['types']['allContext'];
|
|
24
24
|
search: FullSearchSchema<TRouteTree> & RouteById<TRouteTree, TRouteId>['types']['fullSearchSchema'];
|
|
25
|
-
|
|
25
|
+
fetchCount: number;
|
|
26
26
|
shouldReloadDeps: any;
|
|
27
27
|
abortController: AbortController;
|
|
28
|
-
cause: 'enter' | 'stay';
|
|
28
|
+
cause: 'preload' | 'enter' | 'stay';
|
|
29
29
|
}
|
|
30
30
|
export type AnyRouteMatch = RouteMatch<any>;
|
|
31
31
|
export declare function Matches(): React.JSX.Element;
|
|
@@ -22,7 +22,7 @@ export type NavigateFn<TRouteTree extends AnyRoute> = <TFrom extends RoutePaths<
|
|
|
22
22
|
export type MatchRouteFn<TRouteTree extends AnyRoute> = <TFrom extends RoutePaths<TRouteTree> = '/', TTo extends string = '', TResolved = ResolveRelativePath<TFrom, NoInfer<TTo>>>(location: ToOptions<TRouteTree, TFrom, TTo>, opts?: MatchRouteOptions) => false | RouteById<TRouteTree, TResolved>['types']['allParams'];
|
|
23
23
|
export type BuildLocationFn<TRouteTree extends AnyRoute> = (opts: BuildNextOptions) => ParsedLocation;
|
|
24
24
|
export type InjectedHtmlEntry = string | (() => Promise<string> | string);
|
|
25
|
-
export declare
|
|
25
|
+
export declare let routerContext: React.Context<Router<any, Record<string, any>>>;
|
|
26
26
|
export declare function RouterProvider<TRouteTree extends AnyRoute = RegisteredRouter['routeTree'], TDehydrated extends Record<string, any> = Record<string, any>>({ router, ...rest }: RouterProps<TRouteTree, TDehydrated>): React.JSX.Element;
|
|
27
27
|
export declare function getRouteMatch<TRouteTree extends AnyRoute>(state: RouterState<TRouteTree>, id: string): undefined | RouteMatch<TRouteTree>;
|
|
28
28
|
export declare function useRouterState<TSelected = RouterState<RegisteredRouter['routeTree']>>(opts?: {
|
package/build/types/route.d.ts
CHANGED
|
@@ -61,7 +61,7 @@ type BeforeLoadFn<TFullSearchSchema extends Record<string, any>, TParentRoute ex
|
|
|
61
61
|
location: ParsedLocation;
|
|
62
62
|
navigate: NavigateFn<AnyRoute>;
|
|
63
63
|
buildLocation: BuildLocationFn<AnyRoute>;
|
|
64
|
-
cause: 'enter' | 'stay';
|
|
64
|
+
cause: 'preload' | 'enter' | 'stay';
|
|
65
65
|
}) => Promise<TRouteContext> | TRouteContext | void;
|
|
66
66
|
export type UpdatableRouteOptions<TFullSearchSchema extends Record<string, any>> = MetaOptions & {
|
|
67
67
|
caseSensitive?: boolean;
|
|
@@ -102,7 +102,7 @@ export interface LoaderFnContext<TAllParams = {}, TFullSearchSchema extends Reco
|
|
|
102
102
|
location: ParsedLocation<TFullSearchSchema>;
|
|
103
103
|
navigate: (opts: NavigateOptions<AnyRoute>) => Promise<void>;
|
|
104
104
|
parentMatchPromise?: Promise<void>;
|
|
105
|
-
cause: 'enter' | 'stay';
|
|
105
|
+
cause: 'preload' | 'enter' | 'stay';
|
|
106
106
|
}
|
|
107
107
|
export type SearchFilter<T, U = T> = (prev: T) => U;
|
|
108
108
|
export type ResolveId<TParentRoute, TCustomId extends string, TPath extends string> = TParentRoute extends {
|
package/build/types/router.d.ts
CHANGED
|
@@ -41,6 +41,7 @@ export interface RouterOptions<TRouteTree extends AnyRoute, TDehydrated extends
|
|
|
41
41
|
defaultPendingComponent?: RouteComponent;
|
|
42
42
|
defaultPendingMs?: number;
|
|
43
43
|
defaultPendingMinMs?: number;
|
|
44
|
+
defaultPreloadMaxAge?: number;
|
|
44
45
|
caseSensitive?: boolean;
|
|
45
46
|
routeTree?: TRouteTree;
|
|
46
47
|
basepath?: string;
|
|
@@ -63,6 +64,7 @@ export interface RouterState<TRouteTree extends AnyRoute = AnyRoute> {
|
|
|
63
64
|
isTransitioning: boolean;
|
|
64
65
|
matches: RouteMatch<TRouteTree>[];
|
|
65
66
|
pendingMatches?: RouteMatch<TRouteTree>[];
|
|
67
|
+
preloadMatches: RouteMatch<TRouteTree>[];
|
|
66
68
|
location: ParsedLocation<FullSearchSchema<TRouteTree>>;
|
|
67
69
|
resolvedLocation: ParsedLocation<FullSearchSchema<TRouteTree>>;
|
|
68
70
|
lastUpdated: number;
|
|
@@ -87,7 +89,7 @@ export interface BuildNextOptions {
|
|
|
87
89
|
export interface DehydratedRouterState {
|
|
88
90
|
dehydratedMatches: DehydratedRouteMatch[];
|
|
89
91
|
}
|
|
90
|
-
export type DehydratedRouteMatch = Pick<RouteMatch, '
|
|
92
|
+
export type DehydratedRouteMatch = Pick<RouteMatch, 'id' | 'status' | 'updatedAt'>;
|
|
91
93
|
export interface DehydratedRouter {
|
|
92
94
|
state: DehydratedRouterState;
|
|
93
95
|
}
|
|
@@ -1080,9 +1080,13 @@
|
|
|
1080
1080
|
});
|
|
1081
1081
|
}
|
|
1082
1082
|
|
|
1083
|
-
|
|
1083
|
+
exports.routerContext = /*#__PURE__*/React__namespace.createContext(null);
|
|
1084
1084
|
if (typeof document !== 'undefined') {
|
|
1085
|
-
window.__TSR_ROUTER_CONTEXT__
|
|
1085
|
+
if (window.__TSR_ROUTER_CONTEXT__) {
|
|
1086
|
+
exports.routerContext = window.__TSR_ROUTER_CONTEXT__;
|
|
1087
|
+
} else {
|
|
1088
|
+
window.__TSR_ROUTER_CONTEXT__ = exports.routerContext;
|
|
1089
|
+
}
|
|
1086
1090
|
}
|
|
1087
1091
|
function RouterProvider({
|
|
1088
1092
|
router,
|
|
@@ -1098,7 +1102,7 @@
|
|
|
1098
1102
|
}
|
|
1099
1103
|
});
|
|
1100
1104
|
const matches = router.options.InnerWrap ? /*#__PURE__*/React__namespace.createElement(router.options.InnerWrap, null, /*#__PURE__*/React__namespace.createElement(Matches, null)) : /*#__PURE__*/React__namespace.createElement(Matches, null);
|
|
1101
|
-
const provider = /*#__PURE__*/React__namespace.createElement(routerContext.Provider, {
|
|
1105
|
+
const provider = /*#__PURE__*/React__namespace.createElement(exports.routerContext.Provider, {
|
|
1102
1106
|
value: router
|
|
1103
1107
|
}, matches, /*#__PURE__*/React__namespace.createElement(Transitioner, null));
|
|
1104
1108
|
if (router.options.Wrap) {
|
|
@@ -1192,14 +1196,14 @@
|
|
|
1192
1196
|
return null;
|
|
1193
1197
|
}
|
|
1194
1198
|
function getRouteMatch(state, id) {
|
|
1195
|
-
return [...(state.pendingMatches ?? []), ...state.matches].find(d => d.id === id);
|
|
1199
|
+
return [...state.preloadMatches, ...(state.pendingMatches ?? []), ...state.matches].find(d => d.id === id);
|
|
1196
1200
|
}
|
|
1197
1201
|
function useRouterState(opts) {
|
|
1198
1202
|
const router = useRouter();
|
|
1199
1203
|
return useStore(router.__store, opts?.select);
|
|
1200
1204
|
}
|
|
1201
1205
|
function useRouter() {
|
|
1202
|
-
const resolvedContext = typeof document !== 'undefined' ? window.__TSR_ROUTER_CONTEXT__ || routerContext : routerContext;
|
|
1206
|
+
const resolvedContext = typeof document !== 'undefined' ? window.__TSR_ROUTER_CONTEXT__ || exports.routerContext : exports.routerContext;
|
|
1203
1207
|
const value = React__namespace.useContext(resolvedContext);
|
|
1204
1208
|
warning(value, 'useRouter must be used inside a <RouterProvider> component!');
|
|
1205
1209
|
return value;
|
|
@@ -2296,7 +2300,7 @@
|
|
|
2296
2300
|
context: undefined,
|
|
2297
2301
|
abortController: new AbortController(),
|
|
2298
2302
|
shouldReloadDeps: undefined,
|
|
2299
|
-
|
|
2303
|
+
fetchCount: 0,
|
|
2300
2304
|
cause
|
|
2301
2305
|
};
|
|
2302
2306
|
|
|
@@ -2505,10 +2509,13 @@
|
|
|
2505
2509
|
}) => {
|
|
2506
2510
|
let latestPromise;
|
|
2507
2511
|
let firstBadMatchIndex;
|
|
2508
|
-
const
|
|
2512
|
+
const updateMatch = match => {
|
|
2513
|
+
const isPreload = this.state.preloadMatches.find(d => d.id === match.id);
|
|
2514
|
+
const isPending = this.state.pendingMatches?.find(d => d.id === match.id);
|
|
2515
|
+
const matchesKey = isPreload ? 'preloadMatches' : isPending ? 'pendingMatches' : 'matches';
|
|
2509
2516
|
this.__store.setState(s => ({
|
|
2510
2517
|
...s,
|
|
2511
|
-
|
|
2518
|
+
[matchesKey]: s[matchesKey]?.map(d => d.id === match.id ? match : d)
|
|
2512
2519
|
}));
|
|
2513
2520
|
};
|
|
2514
2521
|
|
|
@@ -2561,7 +2568,7 @@
|
|
|
2561
2568
|
from: match.pathname
|
|
2562
2569
|
}),
|
|
2563
2570
|
buildLocation: this.buildLocation,
|
|
2564
|
-
cause: match.cause
|
|
2571
|
+
cause: preload ? 'preload' : match.cause
|
|
2565
2572
|
})) ?? {};
|
|
2566
2573
|
if (isRedirect(beforeLoadContext)) {
|
|
2567
2574
|
throw beforeLoadContext;
|
|
@@ -2591,7 +2598,7 @@
|
|
|
2591
2598
|
const validResolvedMatches = matches.slice(0, firstBadMatchIndex);
|
|
2592
2599
|
const matchPromises = [];
|
|
2593
2600
|
validResolvedMatches.forEach((match, index) => {
|
|
2594
|
-
matchPromises.push((async
|
|
2601
|
+
matchPromises.push(new Promise(async resolve => {
|
|
2595
2602
|
const parentMatchPromise = matchPromises[index - 1];
|
|
2596
2603
|
const route = this.looseRoutesById[match.routeId];
|
|
2597
2604
|
const handleErrorAndRedirect = err => {
|
|
@@ -2606,92 +2613,95 @@
|
|
|
2606
2613
|
let loadPromise;
|
|
2607
2614
|
matches[index] = match = {
|
|
2608
2615
|
...match,
|
|
2609
|
-
fetchedAt: Date.now(),
|
|
2610
2616
|
showPending: false
|
|
2611
2617
|
};
|
|
2618
|
+
let didShowPending = false;
|
|
2612
2619
|
const pendingMs = route.options.pendingMs ?? this.options.defaultPendingMs;
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
};
|
|
2620
|
+
const pendingMinMs = route.options.pendingMinMs ?? this.options.defaultPendingMinMs;
|
|
2621
|
+
const shouldPending = !preload && pendingMs && (route.options.pendingComponent ?? this.options.defaultPendingComponent);
|
|
2622
|
+
const fetch = async () => {
|
|
2623
|
+
if (match.isFetching) {
|
|
2624
|
+
loadPromise = getRouteMatch(this.state, match.id)?.loadPromise;
|
|
2625
|
+
} else {
|
|
2626
|
+
const loaderContext = {
|
|
2627
|
+
params: match.params,
|
|
2628
|
+
search: match.search,
|
|
2629
|
+
preload: !!preload,
|
|
2630
|
+
parentMatchPromise,
|
|
2631
|
+
abortController: match.abortController,
|
|
2632
|
+
context: match.context,
|
|
2633
|
+
location: this.state.location,
|
|
2634
|
+
navigate: opts => this.navigate({
|
|
2635
|
+
...opts,
|
|
2636
|
+
from: match.pathname
|
|
2637
|
+
}),
|
|
2638
|
+
cause: preload ? 'preload' : match.cause
|
|
2639
|
+
};
|
|
2634
2640
|
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2641
|
+
// Default to reloading the route all the time
|
|
2642
|
+
let shouldLoad = true;
|
|
2643
|
+
const shouldReloadFn = route.options.shouldReload;
|
|
2644
|
+
let shouldReloadDeps = typeof shouldReloadFn === 'function' ? shouldReloadFn(loaderContext) : !!(shouldReloadFn ?? true);
|
|
2645
|
+
const compareDeps = () => {
|
|
2646
|
+
if (typeof shouldReloadDeps === 'object') {
|
|
2647
|
+
// compare the deps to see if they've changed
|
|
2648
|
+
shouldLoad = !deepEqual(shouldReloadDeps, match.shouldReloadDeps);
|
|
2649
|
+
} else {
|
|
2650
|
+
shouldLoad = !!shouldReloadDeps;
|
|
2651
|
+
}
|
|
2652
|
+
};
|
|
2653
|
+
|
|
2654
|
+
// If it's the first preload, or the route is entering, or we're
|
|
2655
|
+
// invalidating, we definitely need to load the route
|
|
2656
|
+
if (invalidate) ; else if (preload) {
|
|
2657
|
+
if (!match.fetchCount) ; else {
|
|
2658
|
+
compareDeps();
|
|
2659
|
+
}
|
|
2660
|
+
} else if (match.cause === 'enter') {
|
|
2661
|
+
if (!match.fetchCount) ; else {
|
|
2662
|
+
compareDeps();
|
|
2663
|
+
}
|
|
2645
2664
|
} else {
|
|
2646
|
-
|
|
2665
|
+
compareDeps();
|
|
2666
|
+
}
|
|
2667
|
+
if (typeof shouldReloadDeps === 'object') {
|
|
2668
|
+
matches[index] = match = {
|
|
2669
|
+
...match,
|
|
2670
|
+
shouldReloadDeps
|
|
2671
|
+
};
|
|
2647
2672
|
}
|
|
2648
|
-
}
|
|
2649
2673
|
|
|
2650
|
-
|
|
2651
|
-
|
|
2674
|
+
// If the user doesn't want the route to reload, just
|
|
2675
|
+
// resolve with the existing loader data
|
|
2652
2676
|
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
...match,
|
|
2659
|
-
isFetching: true
|
|
2660
|
-
};
|
|
2661
|
-
const componentsPromise = Promise.all(componentTypes.map(async type => {
|
|
2662
|
-
const component = route.options[type];
|
|
2663
|
-
if (component?.preload) {
|
|
2664
|
-
await component.preload();
|
|
2677
|
+
if (!shouldLoad) {
|
|
2678
|
+
loadPromise = Promise.resolve(match.loaderData);
|
|
2679
|
+
} else {
|
|
2680
|
+
if (match.fetchCount && match.status === 'success') {
|
|
2681
|
+
resolve();
|
|
2665
2682
|
}
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
loadPromise = Promise.all([componentsPromise, loaderPromise]).then(d => d[1]);
|
|
2669
|
-
}
|
|
2670
|
-
}
|
|
2671
|
-
matches[index] = match = {
|
|
2672
|
-
...match,
|
|
2673
|
-
loadPromise
|
|
2674
|
-
};
|
|
2675
|
-
if (!preload) {
|
|
2676
|
-
updatePendingMatch(match);
|
|
2677
|
-
}
|
|
2678
|
-
let didShowPending = false;
|
|
2679
|
-
const pendingMinMs = route.options.pendingMinMs ?? this.options.defaultPendingMinMs;
|
|
2680
|
-
await new Promise(async resolve => {
|
|
2681
|
-
// If the route has a pending component and a pendingMs option,
|
|
2682
|
-
// forcefully show the pending component
|
|
2683
|
-
if (pendingPromise) {
|
|
2684
|
-
pendingPromise.then(() => {
|
|
2685
|
-
if (latestPromise = checkLatest()) return;
|
|
2686
|
-
didShowPending = true;
|
|
2683
|
+
|
|
2684
|
+
// Otherwise, load the route
|
|
2687
2685
|
matches[index] = match = {
|
|
2688
2686
|
...match,
|
|
2689
|
-
|
|
2687
|
+
isFetching: true,
|
|
2688
|
+
fetchCount: match.fetchCount + 1
|
|
2690
2689
|
};
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2690
|
+
const componentsPromise = Promise.all(componentTypes.map(async type => {
|
|
2691
|
+
const component = route.options[type];
|
|
2692
|
+
if (component?.preload) {
|
|
2693
|
+
await component.preload();
|
|
2694
|
+
}
|
|
2695
|
+
}));
|
|
2696
|
+
const loaderPromise = route.options.loader?.(loaderContext);
|
|
2697
|
+
loadPromise = Promise.all([componentsPromise, loaderPromise]).then(d => d[1]);
|
|
2698
|
+
}
|
|
2694
2699
|
}
|
|
2700
|
+
matches[index] = match = {
|
|
2701
|
+
...match,
|
|
2702
|
+
loadPromise
|
|
2703
|
+
};
|
|
2704
|
+
updateMatch(match);
|
|
2695
2705
|
try {
|
|
2696
2706
|
const loaderData = await loadPromise;
|
|
2697
2707
|
if (latestPromise = checkLatest()) return await latestPromise;
|
|
@@ -2732,18 +2742,38 @@
|
|
|
2732
2742
|
// we already moved the pendingMatches to the matches
|
|
2733
2743
|
// state, so we need to update that specific match
|
|
2734
2744
|
if (didShowPending && pendingMinMs && match.showPending) {
|
|
2735
|
-
|
|
2736
|
-
...s,
|
|
2737
|
-
matches: s.matches?.map(d => d.id === match.id ? match : d)
|
|
2738
|
-
}));
|
|
2745
|
+
updateMatch(match);
|
|
2739
2746
|
}
|
|
2740
2747
|
}
|
|
2741
|
-
|
|
2742
|
-
|
|
2748
|
+
updateMatch(match);
|
|
2749
|
+
};
|
|
2750
|
+
if (match.fetchCount && match.status === 'success') {
|
|
2751
|
+
// Background Fetching
|
|
2752
|
+
fetch();
|
|
2753
|
+
} else {
|
|
2754
|
+
// Critical Fetching
|
|
2755
|
+
|
|
2756
|
+
// If we need to potentially show the pending component,
|
|
2757
|
+
// start a timer to show it after the pendingMs
|
|
2758
|
+
if (shouldPending) {
|
|
2759
|
+
new Promise(r => setTimeout(r, pendingMs)).then(async () => {
|
|
2760
|
+
if (latestPromise = checkLatest()) return latestPromise;
|
|
2761
|
+
didShowPending = true;
|
|
2762
|
+
matches[index] = match = {
|
|
2763
|
+
...match,
|
|
2764
|
+
showPending: true
|
|
2765
|
+
};
|
|
2766
|
+
updateMatch(match);
|
|
2767
|
+
resolve();
|
|
2768
|
+
});
|
|
2743
2769
|
}
|
|
2744
|
-
|
|
2745
|
-
}
|
|
2746
|
-
|
|
2770
|
+
await fetch();
|
|
2771
|
+
}
|
|
2772
|
+
resolve();
|
|
2773
|
+
// No Fetching
|
|
2774
|
+
|
|
2775
|
+
resolve();
|
|
2776
|
+
}));
|
|
2747
2777
|
});
|
|
2748
2778
|
await Promise.all(matchPromises);
|
|
2749
2779
|
return matches;
|
|
@@ -2766,20 +2796,32 @@
|
|
|
2766
2796
|
toLocation: next,
|
|
2767
2797
|
pathChanged: pathDidChange
|
|
2768
2798
|
});
|
|
2769
|
-
|
|
2770
|
-
// Match the routes
|
|
2771
|
-
let pendingMatches = this.matchRoutes(next.pathname, next.search, {
|
|
2772
|
-
debug: true
|
|
2773
|
-
});
|
|
2799
|
+
let pendingMatches;
|
|
2774
2800
|
const previousMatches = this.state.matches;
|
|
2801
|
+
this.__store.batch(() => {
|
|
2802
|
+
this.__store.setState(s => ({
|
|
2803
|
+
...s,
|
|
2804
|
+
preloadMatches: s.preloadMatches.filter(d => {
|
|
2805
|
+
return Date.now() - d.updatedAt < (this.options.defaultPreloadMaxAge ?? 3000);
|
|
2806
|
+
})
|
|
2807
|
+
}));
|
|
2775
2808
|
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2809
|
+
// Match the routes
|
|
2810
|
+
pendingMatches = this.matchRoutes(next.pathname, next.search, {
|
|
2811
|
+
debug: true
|
|
2812
|
+
});
|
|
2813
|
+
|
|
2814
|
+
// Ingest the new matches
|
|
2815
|
+
this.__store.setState(s => ({
|
|
2816
|
+
...s,
|
|
2817
|
+
isLoading: true,
|
|
2818
|
+
location: next,
|
|
2819
|
+
pendingMatches,
|
|
2820
|
+
preloadMatches: s.preloadMatches.filter(d => {
|
|
2821
|
+
return !pendingMatches.find(e => e.id === d.id);
|
|
2822
|
+
})
|
|
2823
|
+
}));
|
|
2824
|
+
});
|
|
2783
2825
|
try {
|
|
2784
2826
|
try {
|
|
2785
2827
|
// Load the matches
|
|
@@ -2837,6 +2879,17 @@
|
|
|
2837
2879
|
let matches = this.matchRoutes(next.pathname, next.search, {
|
|
2838
2880
|
throwOnError: true
|
|
2839
2881
|
});
|
|
2882
|
+
const loadedMatchIds = Object.fromEntries([...this.state.matches, ...(this.state.pendingMatches ?? []), ...this.state.preloadMatches]?.map(d => [d.id, true]));
|
|
2883
|
+
this.__store.batch(() => {
|
|
2884
|
+
matches.forEach(match => {
|
|
2885
|
+
if (!loadedMatchIds[match.id]) {
|
|
2886
|
+
this.__store.setState(s => ({
|
|
2887
|
+
...s,
|
|
2888
|
+
preloadMatches: [...s.preloadMatches, match]
|
|
2889
|
+
}));
|
|
2890
|
+
}
|
|
2891
|
+
});
|
|
2892
|
+
});
|
|
2840
2893
|
matches = await this.loadMatches({
|
|
2841
2894
|
matches,
|
|
2842
2895
|
preload: true,
|
|
@@ -2899,7 +2952,7 @@
|
|
|
2899
2952
|
dehydrate = () => {
|
|
2900
2953
|
return {
|
|
2901
2954
|
state: {
|
|
2902
|
-
dehydratedMatches: this.state.matches.map(d => pick(d, ['
|
|
2955
|
+
dehydratedMatches: this.state.matches.map(d => pick(d, ['id', 'status', 'updatedAt', 'loaderData']))
|
|
2903
2956
|
}
|
|
2904
2957
|
};
|
|
2905
2958
|
};
|
|
@@ -2962,6 +3015,7 @@
|
|
|
2962
3015
|
location,
|
|
2963
3016
|
matches: [],
|
|
2964
3017
|
pendingMatches: [],
|
|
3018
|
+
preloadMatches: [],
|
|
2965
3019
|
lastUpdated: Date.now()
|
|
2966
3020
|
};
|
|
2967
3021
|
}
|
|
@@ -3255,7 +3309,6 @@
|
|
|
3255
3309
|
exports.resolvePath = resolvePath;
|
|
3256
3310
|
exports.rootRouteId = rootRouteId;
|
|
3257
3311
|
exports.rootRouteWithContext = rootRouteWithContext;
|
|
3258
|
-
exports.routerContext = routerContext;
|
|
3259
3312
|
exports.shallow = shallow;
|
|
3260
3313
|
exports.stringifySearchWith = stringifySearchWith;
|
|
3261
3314
|
exports.trimPath = trimPath;
|