@tanstack/react-router 0.0.1-beta.215 → 0.0.1-beta.217

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.
@@ -76,6 +76,7 @@ export interface RouteMatch<TRouteTree extends AnyRoute = AnyRoute, TRouteId ext
76
76
  routeSearch: RouteById<TRouteTree, TRouteId>['types']['searchSchema'];
77
77
  search: FullSearchSchema<TRouteTree> & RouteById<TRouteTree, TRouteId>['types']['fullSearchSchema'];
78
78
  fetchedAt: number;
79
+ shouldReloadDeps: any;
79
80
  abortController: AbortController;
80
81
  }
81
82
  export type AnyRouteMatch = RouteMatch<any>;
@@ -34,6 +34,7 @@ export type ParamsFallback<TPath extends string, TParams> = unknown extends TPar
34
34
  export type BaseRouteOptions<TParentRoute extends AnyRoute = AnyRoute, TCustomId extends string = string, TPath extends string = string, TSearchSchema extends Record<string, any> = {}, TFullSearchSchema extends Record<string, any> = TSearchSchema, TParams extends AnyPathParams = {}, TAllParams = ParamsFallback<TPath, TParams>, TRouteContext extends RouteContext = RouteContext, TAllContext extends Record<string, any> = AnyContext, TLoaderData extends any = unknown> = RoutePathOptions<TCustomId, TPath> & {
35
35
  getParentRoute: () => TParentRoute;
36
36
  validateSearch?: SearchSchemaValidator<TSearchSchema>;
37
+ shouldReload?: boolean | ((match: LoaderFnContext<TAllParams, TFullSearchSchema, TAllContext, TRouteContext>) => any);
37
38
  } & (keyof PickRequired<RouteContext> extends never ? {
38
39
  beforeLoad?: BeforeLoadFn<TFullSearchSchema, TParentRoute, TAllParams, TRouteContext>;
39
40
  } : {
@@ -85,9 +86,7 @@ export type DefinedPathParamWarning = 'Path params cannot be redefined by child
85
86
  export type ParentParams<TParentParams> = AnyPathParams extends TParentParams ? {} : {
86
87
  [Key in keyof TParentParams]?: DefinedPathParamWarning;
87
88
  };
88
- export type RouteLoadFn<TAllParams = {}, TFullSearchSchema extends Record<string, any> = {}, TAllContext extends Record<string, any> = AnyContext, TRouteContext extends Record<string, any> = AnyContext, TLoaderData extends any = unknown> = (match: LoaderFnContext<TAllParams, TFullSearchSchema, TAllContext, TRouteContext> & {
89
- parentMatchPromise?: Promise<void>;
90
- }) => Promise<TLoaderData> | TLoaderData;
89
+ export type RouteLoadFn<TAllParams = {}, TFullSearchSchema extends Record<string, any> = {}, TAllContext extends Record<string, any> = AnyContext, TRouteContext extends Record<string, any> = AnyContext, TLoaderData extends any = unknown> = (match: LoaderFnContext<TAllParams, TFullSearchSchema, TAllContext, TRouteContext>) => Promise<TLoaderData> | TLoaderData;
91
90
  export interface LoaderFnContext<TAllParams = {}, TFullSearchSchema extends Record<string, any> = {}, TAllContext extends Record<string, any> = AnyContext, TRouteContext extends Record<string, any> = AnyContext> {
92
91
  abortController: AbortController;
93
92
  preload: boolean;
@@ -96,6 +95,8 @@ export interface LoaderFnContext<TAllParams = {}, TFullSearchSchema extends Reco
96
95
  context: Expand<Assign<TAllContext, TRouteContext>>;
97
96
  location: ParsedLocation<TFullSearchSchema>;
98
97
  navigate: (opts: NavigateOptions<AnyRoute>) => Promise<void>;
98
+ parentMatchPromise?: Promise<void>;
99
+ cause: 'enter' | 'stay';
99
100
  }
100
101
  export type SearchFilter<T, U = T> = (prev: T) => U;
101
102
  export type ResolveId<TParentRoute, TCustomId extends string, TPath extends string> = TParentRoute extends {
@@ -48,7 +48,7 @@ export declare function pick<T, K extends keyof T>(parent: T, keys: K[]): Pick<T
48
48
  */
49
49
  export declare function replaceEqualDeep<T>(prev: any, _next: T): T;
50
50
  export declare function isPlainObject(o: any): boolean;
51
- export declare function partialDeepEqual(a: any, b: any): boolean;
51
+ export declare function deepEqual(a: any, b: any, partial?: boolean): boolean;
52
52
  export declare function useStableCallback<T extends (...args: any[]) => any>(fn: T): T;
53
53
  export declare function shallow<T>(objA: T, objB: T): boolean;
54
54
  export type StrictOrFrom<TFrom> = {
@@ -558,7 +558,7 @@
558
558
  function hasObjectPrototype(o) {
559
559
  return Object.prototype.toString.call(o) === '[object Object]';
560
560
  }
561
- function partialDeepEqual(a, b) {
561
+ function deepEqual(a, b, partial = false) {
562
562
  if (a === b) {
563
563
  return true;
564
564
  }
@@ -566,10 +566,15 @@
566
566
  return false;
567
567
  }
568
568
  if (isPlainObject(a) && isPlainObject(b)) {
569
- return !Object.keys(b).some(key => !partialDeepEqual(a[key], b[key]));
569
+ const aKeys = Object.keys(a);
570
+ const bKeys = Object.keys(b);
571
+ if (!partial && aKeys.length !== bKeys.length) {
572
+ return false;
573
+ }
574
+ return !bKeys.some(key => !(key in a) || !deepEqual(a[key], b[key], partial));
570
575
  }
571
576
  if (Array.isArray(a) && Array.isArray(b)) {
572
- return !(a.length !== b.length || a.some((item, index) => !partialDeepEqual(item, b[index])));
577
+ return !a.some((item, index) => !deepEqual(item, b[index], partial));
573
578
  }
574
579
  return false;
575
580
  }
@@ -1356,6 +1361,7 @@
1356
1361
  loadPromise: Promise.resolve(),
1357
1362
  context: undefined,
1358
1363
  abortController: new AbortController(),
1364
+ shouldReloadDeps: undefined,
1359
1365
  fetchedAt: 0
1360
1366
  };
1361
1367
  return routeMatch;
@@ -1687,17 +1693,8 @@
1687
1693
  if (match.isFetching) {
1688
1694
  loadPromise = getRouteMatch(state, match.id)?.loadPromise;
1689
1695
  } else {
1690
- matches[index] = match = {
1691
- ...match,
1692
- isFetching: true
1693
- };
1694
- const componentsPromise = Promise.all(componentTypes.map(async type => {
1695
- const component = route.options[type];
1696
- if (component?.preload) {
1697
- await component.preload();
1698
- }
1699
- }));
1700
- const loaderPromise = route.options.loader?.({
1696
+ const cause = state.matches.find(d => d.id === match.id) ? 'stay' : 'enter';
1697
+ const loaderContext = {
1701
1698
  params: match.params,
1702
1699
  search: match.search,
1703
1700
  preload: !!preload,
@@ -1708,9 +1705,42 @@
1708
1705
  navigate: opts => navigate({
1709
1706
  ...opts,
1710
1707
  from: match.pathname
1711
- })
1712
- });
1713
- loadPromise = Promise.all([componentsPromise, loaderPromise]).then(d => d[1]);
1708
+ }),
1709
+ cause
1710
+ };
1711
+
1712
+ // Default to reloading the route all the time
1713
+ let shouldReload = true;
1714
+ let shouldReloadDeps = typeof route.options.shouldReload === 'function' ? route.options.shouldReload?.(loaderContext) : !!route.options.shouldReload;
1715
+ if (typeof shouldReloadDeps === 'object') {
1716
+ // compare the deps to see if they've changed
1717
+ shouldReload = !deepEqual(shouldReloadDeps, match.shouldReloadDeps);
1718
+ console.log(shouldReloadDeps, match.shouldReloadDeps, shouldReload);
1719
+ match.shouldReloadDeps = shouldReloadDeps;
1720
+ } else {
1721
+ shouldReload = !!shouldReloadDeps;
1722
+ }
1723
+
1724
+ // If the user doesn't want the route to reload, just
1725
+ // resolve with the existing loader data
1726
+
1727
+ if (!shouldReload) {
1728
+ loadPromise = Promise.resolve(match.loaderData);
1729
+ } else {
1730
+ // Otherwise, load the route
1731
+ matches[index] = match = {
1732
+ ...match,
1733
+ isFetching: true
1734
+ };
1735
+ const componentsPromise = Promise.all(componentTypes.map(async type => {
1736
+ const component = route.options[type];
1737
+ if (component?.preload) {
1738
+ await component.preload();
1739
+ }
1740
+ }));
1741
+ const loaderPromise = route.options.loader?.(loaderContext);
1742
+ loadPromise = Promise.all([componentsPromise, loaderPromise]).then(d => d[1]);
1743
+ }
1714
1744
  }
1715
1745
  matches[index] = match = {
1716
1746
  ...match,
@@ -1892,7 +1922,7 @@
1892
1922
  // Combine the matches based on user options
1893
1923
  const pathTest = activeOptions?.exact ? latestLocationRef.current.pathname === next.pathname : pathIsFuzzyEqual;
1894
1924
  const hashTest = activeOptions?.includeHash ? latestLocationRef.current.hash === next.hash : true;
1895
- const searchTest = activeOptions?.includeSearch ?? true ? partialDeepEqual(latestLocationRef.current.search, next.search) : true;
1925
+ const searchTest = activeOptions?.includeSearch ?? true ? deepEqual(latestLocationRef.current.search, next.search, true) : true;
1896
1926
 
1897
1927
  // The final "active" test
1898
1928
  const isActive = pathTest && hashTest && searchTest;
@@ -2023,7 +2053,7 @@
2023
2053
  return false;
2024
2054
  }
2025
2055
  if (match && (opts?.includeSearch ?? true)) {
2026
- return partialDeepEqual(baseLocation.search, next.search) ? match : false;
2056
+ return deepEqual(baseLocation.search, next.search, true) ? match : false;
2027
2057
  }
2028
2058
  return match;
2029
2059
  });
@@ -2749,6 +2779,7 @@
2749
2779
  exports.createMemoryHistory = createMemoryHistory;
2750
2780
  exports.createRouteMask = createRouteMask;
2751
2781
  exports.decode = decode;
2782
+ exports.deepEqual = deepEqual;
2752
2783
  exports.defaultParseSearch = defaultParseSearch;
2753
2784
  exports.defaultStringifySearch = defaultStringifySearch;
2754
2785
  exports.encode = encode;
@@ -2769,7 +2800,6 @@
2769
2800
  exports.matchesContext = matchesContext;
2770
2801
  exports.parsePathname = parsePathname;
2771
2802
  exports.parseSearchWith = parseSearchWith;
2772
- exports.partialDeepEqual = partialDeepEqual;
2773
2803
  exports.pick = pick;
2774
2804
  exports.redirect = redirect;
2775
2805
  exports.replaceEqualDeep = replaceEqualDeep;