@tanstack/react-router 0.0.1-beta.61 → 0.0.1-beta.62

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.
@@ -89,9 +89,9 @@
89
89
  const previous = this.state;
90
90
  this.state = this.options?.updateFn ? this.options.updateFn(previous)(updater) : updater(previous);
91
91
  if (this.state === previous) return;
92
+ this.options?.onUpdate?.(this.state, previous);
92
93
  this.queue.push(() => {
93
94
  this.listeners.forEach(listener => listener(this.state, previous));
94
- this.options?.onUpdate?.(this.state, previous);
95
95
  });
96
96
  this.#flush();
97
97
  };
@@ -577,7 +577,9 @@
577
577
  this.options = options || {};
578
578
  this.isRoot = !options?.getParentRoute;
579
579
  }
580
- init = () => {
580
+ init = opts => {
581
+ this.originalIndex = opts.originalIndex;
582
+ this.router = opts.router;
581
583
  const allOptions = this.options;
582
584
  const isRoot = !allOptions?.path && !allOptions?.id;
583
585
  const parent = this.options?.getParentRoute?.();
@@ -625,6 +627,9 @@
625
627
  constructor(options) {
626
628
  super(options);
627
629
  }
630
+ static withRouterContext = () => {
631
+ return options => new RootRoute(options);
632
+ };
628
633
  }
629
634
 
630
635
  // const rootRoute = new RootRoute({
@@ -689,8 +694,13 @@
689
694
  routeSearch: {},
690
695
  search: {},
691
696
  status: 'idle'
697
+ }, {
698
+ onUpdate: next => {
699
+ this.state = next;
700
+ }
692
701
  })
693
702
  });
703
+ this.state = this.store.state;
694
704
  if (!this.#hasLoaders()) {
695
705
  this.store.setState(s => ({
696
706
  ...s,
@@ -698,12 +708,66 @@
698
708
  }));
699
709
  }
700
710
  }
711
+ #hasLoaders = () => {
712
+ return !!(this.route.options.onLoad || componentTypes.some(d => this.route.options[d]?.preload));
713
+ };
714
+ __init = opts => {
715
+ // Validate the search params and stabilize them
716
+ this.parentMatch = opts.parentMatch;
717
+ const parentSearch = this.parentMatch?.state.search ?? this.router.state.latestLocation.search;
718
+ try {
719
+ const validator = typeof this.route.options.validateSearch === 'object' ? this.route.options.validateSearch.parse : this.route.options.validateSearch;
720
+ let nextSearch = validator?.(parentSearch) ?? {};
721
+ this.store.setState(s => ({
722
+ ...s,
723
+ routeSearch: nextSearch,
724
+ search: {
725
+ ...parentSearch,
726
+ ...nextSearch
727
+ }
728
+ }));
729
+ componentTypes.map(async type => {
730
+ const component = this.route.options[type];
731
+ if (typeof this[type] !== 'function') {
732
+ this[type] = component;
733
+ }
734
+ });
735
+ const parent = this.parentMatch;
736
+ this.routeContext = this.route.options.getContext?.({
737
+ parentContext: parent?.routeContext,
738
+ context: parent?.context,
739
+ params: this.params,
740
+ search: this.state.search
741
+ }) || {};
742
+ this.context = parent ? {
743
+ ...parent.context,
744
+ ...this.routeContext
745
+ } : {
746
+ ...this.router?.options.context,
747
+ ...this.routeContext
748
+ };
749
+ } catch (err) {
750
+ console.error(err);
751
+ const error = new Error('Invalid search params found', {
752
+ cause: err
753
+ });
754
+ error.code = 'INVALID_SEARCH_PARAMS';
755
+ this.store.setState(s => ({
756
+ ...s,
757
+ status: 'error',
758
+ error: error
759
+ }));
760
+
761
+ // Do not proceed with loading the route
762
+ return;
763
+ }
764
+ };
701
765
  cancel = () => {
702
766
  this.abortController?.abort();
703
767
  };
704
768
  load = async opts => {
705
769
  // If the match is invalid, errored or idle, trigger it to load
706
- if (this.store.state.status !== 'pending') {
770
+ if (this.state.status !== 'pending') {
707
771
  await this.fetch(opts);
708
772
  }
709
773
  };
@@ -720,7 +784,7 @@
720
784
  // If the match was in an error state, set it
721
785
  // to a loading state again. Otherwise, keep it
722
786
  // as loading or resolved
723
- if (this.store.state.status === 'idle') {
787
+ if (this.state.status === 'idle') {
724
788
  this.store.setState(s => ({
725
789
  ...s,
726
790
  status: 'pending'
@@ -742,9 +806,11 @@
742
806
  if (this.route.options.onLoad) {
743
807
  return this.route.options.onLoad({
744
808
  params: this.params,
745
- search: this.store.state.search,
809
+ search: this.state.search,
746
810
  signal: this.abortController.signal,
747
- preload: !!opts?.preload
811
+ preload: !!opts?.preload,
812
+ routeContext: this.routeContext,
813
+ context: this.context
748
814
  });
749
815
  }
750
816
  return;
@@ -772,50 +838,6 @@
772
838
  });
773
839
  return this.__loadPromise;
774
840
  };
775
- #hasLoaders = () => {
776
- return !!(this.route.options.onLoad || componentTypes.some(d => this.route.options[d]?.preload));
777
- };
778
- __setParentMatch = parentMatch => {
779
- if (!this.parentMatch && parentMatch) {
780
- this.parentMatch = parentMatch;
781
- }
782
- };
783
- __validate = () => {
784
- // Validate the search params and stabilize them
785
- const parentSearch = this.parentMatch?.store.state.search ?? this.router.store.state.latestLocation.search;
786
- try {
787
- const validator = typeof this.route.options.validateSearch === 'object' ? this.route.options.validateSearch.parse : this.route.options.validateSearch;
788
- let nextSearch = validator?.(parentSearch) ?? {};
789
- this.store.setState(s => ({
790
- ...s,
791
- routeSearch: nextSearch,
792
- search: {
793
- ...parentSearch,
794
- ...nextSearch
795
- }
796
- }));
797
- componentTypes.map(async type => {
798
- const component = this.route.options[type];
799
- if (typeof this[type] !== 'function') {
800
- this[type] = component;
801
- }
802
- });
803
- } catch (err) {
804
- console.error(err);
805
- const error = new Error('Invalid search params found', {
806
- cause: err
807
- });
808
- error.code = 'INVALID_SEARCH_PARAMS';
809
- this.store.setState(s => ({
810
- ...s,
811
- status: 'error',
812
- error: error
813
- }));
814
-
815
- // Do not proceed with loading the route
816
- return;
817
- }
818
- };
819
841
  }
820
842
 
821
843
  const defaultParseSearch = parseSearchWith(JSON.parse);
@@ -900,7 +922,12 @@
900
922
  parseSearch: options?.parseSearch ?? defaultParseSearch,
901
923
  fetchServerDataFn: options?.fetchServerDataFn ?? defaultFetchServerDataFn
902
924
  };
903
- this.store = new Store(getInitialRouterState());
925
+ this.store = new Store(getInitialRouterState(), {
926
+ onUpdate: state => {
927
+ this.state = state;
928
+ }
929
+ });
930
+ this.state = this.store.state;
904
931
  this.basepath = '';
905
932
  this.update(options);
906
933
 
@@ -914,7 +941,7 @@
914
941
  // Mount only does anything on the client
915
942
  if (!isServer) {
916
943
  // If the router matches are empty, load the matches
917
- if (!this.store.state.currentMatches.length) {
944
+ if (!this.state.currentMatches.length) {
918
945
  this.load();
919
946
  }
920
947
  const visibilityChangeEvent = 'visibilitychange';
@@ -953,7 +980,9 @@
953
980
  currentLocation: parsedLocation
954
981
  }));
955
982
  this.#unsubHistory = this.history.listen(() => {
956
- this.load(this.#parseLocation(this.store.state.latestLocation));
983
+ this.load({
984
+ next: this.#parseLocation(this.state.latestLocation)
985
+ });
957
986
  });
958
987
  }
959
988
  const {
@@ -979,11 +1008,11 @@
979
1008
  });
980
1009
  };
981
1010
  cancelMatches = () => {
982
- [...this.store.state.currentMatches, ...(this.store.state.pendingMatches || [])].forEach(match => {
1011
+ [...this.state.currentMatches, ...(this.state.pendingMatches || [])].forEach(match => {
983
1012
  match.cancel();
984
1013
  });
985
1014
  };
986
- load = async next => {
1015
+ load = async opts => {
987
1016
  let now = Date.now();
988
1017
  const startedAt = now;
989
1018
  this.startedLoadingAt = startedAt;
@@ -992,29 +1021,31 @@
992
1021
  this.cancelMatches();
993
1022
  let matches;
994
1023
  this.store.batch(() => {
995
- if (next) {
1024
+ if (opts?.next) {
996
1025
  // Ingest the new location
997
1026
  this.store.setState(s => ({
998
1027
  ...s,
999
- latestLocation: next
1028
+ latestLocation: opts.next
1000
1029
  }));
1001
1030
  }
1002
1031
 
1003
1032
  // Match the routes
1004
- matches = this.matchRoutes(this.store.state.latestLocation.pathname, {
1033
+ matches = this.matchRoutes(this.state.latestLocation.pathname, {
1005
1034
  strictParseParams: true
1006
1035
  });
1007
1036
  this.store.setState(s => ({
1008
1037
  ...s,
1009
1038
  status: 'pending',
1010
1039
  pendingMatches: matches,
1011
- pendingLocation: this.store.state.latestLocation
1040
+ pendingLocation: this.state.latestLocation
1012
1041
  }));
1013
1042
  });
1014
1043
 
1015
1044
  // Load the matches
1016
1045
  try {
1017
- await this.loadMatches(matches);
1046
+ await this.loadMatches(matches
1047
+ // opts
1048
+ );
1018
1049
  } catch (err) {
1019
1050
  console.warn(err);
1020
1051
  invariant(false, 'Matches failed to load due to error above ☝️. Navigation cancelled!');
@@ -1023,7 +1054,7 @@
1023
1054
  // Ignore side-effects of outdated side-effects
1024
1055
  return this.navigationPromise;
1025
1056
  }
1026
- const previousMatches = this.store.state.currentMatches;
1057
+ const previousMatches = this.state.currentMatches;
1027
1058
  const exiting = [],
1028
1059
  staying = [];
1029
1060
  previousMatches.forEach(d => {
@@ -1040,11 +1071,11 @@
1040
1071
  exiting.forEach(d => {
1041
1072
  d.__onExit?.({
1042
1073
  params: d.params,
1043
- search: d.store.state.routeSearch
1074
+ search: d.state.routeSearch
1044
1075
  });
1045
1076
 
1046
1077
  // Clear non-loading error states when match leaves
1047
- if (d.store.state.status === 'error') {
1078
+ if (d.state.status === 'error') {
1048
1079
  this.store.setState(s => ({
1049
1080
  ...s,
1050
1081
  status: 'idle',
@@ -1055,21 +1086,19 @@
1055
1086
  staying.forEach(d => {
1056
1087
  d.route.options.onTransition?.({
1057
1088
  params: d.params,
1058
- search: d.store.state.routeSearch
1089
+ search: d.state.routeSearch
1059
1090
  });
1060
1091
  });
1061
1092
  entering.forEach(d => {
1062
1093
  d.__onExit = d.route.options.onLoaded?.({
1063
1094
  params: d.params,
1064
- search: d.store.state.search
1095
+ search: d.state.search
1065
1096
  });
1066
- // delete this.store.state.matchCache[d.id] // TODO:
1067
1097
  });
1068
-
1069
1098
  this.store.setState(s => ({
1070
1099
  ...s,
1071
1100
  status: 'idle',
1072
- currentLocation: this.store.state.latestLocation,
1101
+ currentLocation: this.state.latestLocation,
1073
1102
  currentMatches: matches,
1074
1103
  pendingLocation: undefined,
1075
1104
  pendingMatches: undefined
@@ -1082,7 +1111,7 @@
1082
1111
  invariant(route, `Route with id "${id}" not found`);
1083
1112
  return route;
1084
1113
  };
1085
- loadRoute = async (navigateOpts = this.store.state.latestLocation) => {
1114
+ loadRoute = async (navigateOpts = this.state.latestLocation) => {
1086
1115
  const next = this.buildNext(navigateOpts);
1087
1116
  const matches = this.matchRoutes(next.pathname, {
1088
1117
  strictParseParams: true
@@ -1090,7 +1119,7 @@
1090
1119
  await this.loadMatches(matches);
1091
1120
  return matches;
1092
1121
  };
1093
- preloadRoute = async (navigateOpts = this.store.state.latestLocation) => {
1122
+ preloadRoute = async (navigateOpts = this.state.latestLocation) => {
1094
1123
  const next = this.buildNext(navigateOpts);
1095
1124
  const matches = this.matchRoutes(next.pathname, {
1096
1125
  strictParseParams: true
@@ -1105,7 +1134,7 @@
1105
1134
  if (!this.routeTree) {
1106
1135
  return matches;
1107
1136
  }
1108
- const existingMatches = [...this.store.state.currentMatches, ...(this.store.state.pendingMatches ?? [])];
1137
+ const existingMatches = [...this.state.currentMatches, ...(this.state.pendingMatches ?? [])];
1109
1138
  const findInRouteTree = async routes => {
1110
1139
  const parentMatch = last(matches);
1111
1140
  let params = parentMatch?.params ?? {};
@@ -1151,9 +1180,7 @@
1151
1180
  matchingRoutes.forEach(foundRoute => {
1152
1181
  const interpolatedPath = interpolatePath(foundRoute.path, params);
1153
1182
  const matchId = interpolatePath(foundRoute.id, params, true);
1154
- const match = existingMatches.find(d => d.id === matchId) ||
1155
- // this.store.state.matchCache[matchId]?.match || // TODO:
1156
- new RouteMatch(this, foundRoute, {
1183
+ const match = existingMatches.find(d => d.id === matchId) || new RouteMatch(this, foundRoute, {
1157
1184
  id: matchId,
1158
1185
  params,
1159
1186
  pathname: joinPaths([this.basepath, interpolatedPath])
@@ -1169,14 +1196,8 @@
1169
1196
  findInRouteTree([this.routeTree]);
1170
1197
  return matches;
1171
1198
  };
1172
- loadMatches = async (resolvedMatches, loaderOpts) => {
1173
- linkMatches(resolvedMatches);
1174
-
1175
- // this.cleanMatchCache()
1176
- resolvedMatches.forEach(async match => {
1177
- // Validate the match (loads search params etc)
1178
- match.__validate();
1179
- });
1199
+ loadMatches = async (resolvedMatches, opts) => {
1200
+ initMatches(resolvedMatches);
1180
1201
 
1181
1202
  // Check each match middleware to see if the route can be accessed
1182
1203
  await Promise.all(resolvedMatches.map(async match => {
@@ -1186,7 +1207,7 @@
1186
1207
  match
1187
1208
  });
1188
1209
  } catch (err) {
1189
- if (!loaderOpts?.preload) {
1210
+ if (!opts?.preload) {
1190
1211
  match.route.options.onLoadError?.(err);
1191
1212
  }
1192
1213
  throw err;
@@ -1194,14 +1215,16 @@
1194
1215
  }));
1195
1216
  const matchPromises = resolvedMatches.map(async (match, index) => {
1196
1217
  const prevMatch = resolvedMatches[1];
1197
- const search = match.store.state.search;
1198
- if (search.__data?.matchId && search.__data.matchId !== match.id) {
1199
- return;
1200
- }
1218
+ match.state.search;
1219
+
1220
+ // if (opts?.filter && !opts.filter(match)) {
1221
+ // return
1222
+ // }
1223
+
1201
1224
  match.load({
1202
- preload: loaderOpts?.preload
1225
+ preload: opts?.preload
1203
1226
  });
1204
- if (match.store.state.status !== 'success' && match.__loadPromise) {
1227
+ if (match.state.status !== 'success' && match.__loadPromise) {
1205
1228
  // Wait for the first sign of activity from the match
1206
1229
  await match.__loadPromise;
1207
1230
  }
@@ -1258,15 +1281,15 @@
1258
1281
  };
1259
1282
  const next = this.buildNext(location);
1260
1283
  if (opts?.pending) {
1261
- if (!this.store.state.pendingLocation) {
1284
+ if (!this.state.pendingLocation) {
1262
1285
  return false;
1263
1286
  }
1264
- return matchPathname(this.basepath, this.store.state.pendingLocation.pathname, {
1287
+ return matchPathname(this.basepath, this.state.pendingLocation.pathname, {
1265
1288
  ...opts,
1266
1289
  to: next.pathname
1267
1290
  });
1268
1291
  }
1269
- return matchPathname(this.basepath, this.store.state.currentLocation.pathname, {
1292
+ return matchPathname(this.basepath, this.state.currentLocation.pathname, {
1270
1293
  ...opts,
1271
1294
  to: next.pathname
1272
1295
  });
@@ -1312,11 +1335,11 @@
1312
1335
  const preloadDelay = userPreloadDelay ?? this.options.defaultPreloadDelay ?? 0;
1313
1336
 
1314
1337
  // Compare path/hash for matches
1315
- const pathIsEqual = this.store.state.currentLocation.pathname === next.pathname;
1316
- const currentPathSplit = this.store.state.currentLocation.pathname.split('/');
1338
+ const pathIsEqual = this.state.currentLocation.pathname === next.pathname;
1339
+ const currentPathSplit = this.state.currentLocation.pathname.split('/');
1317
1340
  const nextPathSplit = next.pathname.split('/');
1318
1341
  const pathIsFuzzyEqual = nextPathSplit.every((d, i) => d === currentPathSplit[i]);
1319
- const hashIsEqual = this.store.state.currentLocation.hash === next.hash;
1342
+ const hashIsEqual = this.state.currentLocation.hash === next.hash;
1320
1343
  // Combine the matches based on user options
1321
1344
  const pathTest = activeOptions?.exact ? pathIsEqual : pathIsFuzzyEqual;
1322
1345
  const hashTest = activeOptions?.includeHash ? hashIsEqual : true;
@@ -1379,21 +1402,18 @@
1379
1402
  dehydrate = () => {
1380
1403
  return {
1381
1404
  state: {
1382
- ...pick(this.store.state, ['latestLocation', 'currentLocation', 'status', 'lastUpdated']),
1383
- currentMatches: this.store.state.currentMatches.map(match => ({
1405
+ ...pick(this.state, ['latestLocation', 'currentLocation', 'status', 'lastUpdated']),
1406
+ currentMatches: this.state.currentMatches.map(match => ({
1384
1407
  id: match.id,
1385
1408
  state: {
1386
- ...pick(match.store.state, ['status'])
1409
+ status: match.state.status
1387
1410
  }
1388
1411
  }))
1389
- },
1390
- context: this.options.context
1412
+ }
1391
1413
  };
1392
1414
  };
1393
1415
  hydrate = dehydratedRouter => {
1394
1416
  this.store.setState(s => {
1395
- this.options.context = dehydratedRouter.context;
1396
-
1397
1417
  // Match the routes
1398
1418
  const currentMatches = this.matchRoutes(dehydratedRouter.state.latestLocation.pathname, {
1399
1419
  strictParseParams: true
@@ -1406,7 +1426,7 @@
1406
1426
  ...dehydratedMatch.state
1407
1427
  }));
1408
1428
  });
1409
- currentMatches.forEach(match => match.__validate());
1429
+ initMatches(currentMatches);
1410
1430
  return {
1411
1431
  ...s,
1412
1432
  ...dehydratedRouter.state,
@@ -1417,9 +1437,10 @@
1417
1437
  #buildRouteTree = routeTree => {
1418
1438
  const recurseRoutes = routes => {
1419
1439
  routes.forEach((route, i) => {
1420
- route.init();
1421
- route.originalIndex = i;
1422
- route.router = this;
1440
+ route.init({
1441
+ originalIndex: i,
1442
+ router: this
1443
+ });
1423
1444
  const existingRoute = this.routesById[route.id];
1424
1445
  if (existingRoute) {
1425
1446
  {
@@ -1457,9 +1478,9 @@
1457
1478
  this.load();
1458
1479
  };
1459
1480
  #buildLocation = (dest = {}) => {
1460
- const fromPathname = dest.fromCurrent ? this.store.state.latestLocation.pathname : dest.from ?? this.store.state.latestLocation.pathname;
1481
+ const fromPathname = dest.fromCurrent ? this.state.latestLocation.pathname : dest.from ?? this.state.latestLocation.pathname;
1461
1482
  let pathname = resolvePath(this.basepath ?? '/', fromPathname, `${dest.to ?? '.'}`);
1462
- const fromMatches = this.matchRoutes(this.store.state.latestLocation.pathname, {
1483
+ const fromMatches = this.matchRoutes(this.state.latestLocation.pathname, {
1463
1484
  strictParseParams: true
1464
1485
  });
1465
1486
  const toMatches = this.matchRoutes(pathname);
@@ -1475,7 +1496,7 @@
1475
1496
  pathname = interpolatePath(pathname, nextParams ?? {});
1476
1497
 
1477
1498
  // Pre filters first
1478
- const preFilteredSearch = dest.__preSearchFilters?.length ? dest.__preSearchFilters?.reduce((prev, next) => next(prev), this.store.state.latestLocation.search) : this.store.state.latestLocation.search;
1499
+ const preFilteredSearch = dest.__preSearchFilters?.length ? dest.__preSearchFilters?.reduce((prev, next) => next(prev), this.state.latestLocation.search) : this.state.latestLocation.search;
1479
1500
 
1480
1501
  // Then the link/navigate function
1481
1502
  const destSearch = dest.search === true ? preFilteredSearch // Preserve resolvedFrom true
@@ -1485,15 +1506,15 @@
1485
1506
 
1486
1507
  // Then post filters
1487
1508
  const postFilteredSearch = dest.__postSearchFilters?.length ? dest.__postSearchFilters.reduce((prev, next) => next(prev), destSearch) : destSearch;
1488
- const search = replaceEqualDeep(this.store.state.latestLocation.search, postFilteredSearch);
1509
+ const search = replaceEqualDeep(this.state.latestLocation.search, postFilteredSearch);
1489
1510
  const searchStr = this.options.stringifySearch(search);
1490
- let hash = dest.hash === true ? this.store.state.latestLocation.hash : functionalUpdate(dest.hash, this.store.state.latestLocation.hash);
1511
+ let hash = dest.hash === true ? this.state.latestLocation.hash : functionalUpdate(dest.hash, this.state.latestLocation.hash);
1491
1512
  hash = hash ? `#${hash}` : '';
1492
1513
  return {
1493
1514
  pathname,
1494
1515
  search,
1495
1516
  searchStr,
1496
- state: this.store.state.latestLocation.state,
1517
+ state: this.state.latestLocation.state,
1497
1518
  hash,
1498
1519
  href: `${pathname}${searchStr}${hash}`,
1499
1520
  key: dest.key
@@ -1507,7 +1528,7 @@
1507
1528
  if (!location.replace) {
1508
1529
  nextAction = 'push';
1509
1530
  }
1510
- const isSameUrl = this.store.state.latestLocation.href === next.href;
1531
+ const isSameUrl = this.state.latestLocation.href === next.href;
1511
1532
  if (isSameUrl && !next.key) {
1512
1533
  nextAction = 'replace';
1513
1534
  }
@@ -1517,7 +1538,7 @@
1517
1538
  ...next.state
1518
1539
  });
1519
1540
 
1520
- // this.load(this.#parseLocation(this.store.state.latestLocation))
1541
+ // this.load(this.#parseLocation(this.state.latestLocation))
1521
1542
 
1522
1543
  return this.navigationPromise = new Promise(resolve => {
1523
1544
  const previousNavigationResolve = this.resolveNavigation;
@@ -1543,12 +1564,12 @@
1543
1564
  function isCtrlEvent(e) {
1544
1565
  return !!(e.metaKey || e.altKey || e.ctrlKey || e.shiftKey);
1545
1566
  }
1546
- function linkMatches(matches) {
1567
+ function initMatches(matches) {
1547
1568
  matches.forEach((match, index) => {
1548
- const parent = matches[index - 1];
1549
- if (parent) {
1550
- match.__setParentMatch(parent);
1551
- }
1569
+ const parentMatch = matches[index - 1];
1570
+ match.__init({
1571
+ parentMatch
1572
+ });
1552
1573
  });
1553
1574
  }
1554
1575
 
@@ -1624,7 +1645,7 @@
1624
1645
  //
1625
1646
 
1626
1647
  function useLinkProps(options) {
1627
- const router = useRouter();
1648
+ const router = useRouterContext();
1628
1649
  const {
1629
1650
  // custom props
1630
1651
  type,
@@ -1749,7 +1770,7 @@
1749
1770
  ...rest
1750
1771
  }) {
1751
1772
  router.update(rest);
1752
- const currentMatches = useStore(router.store, s => s.currentMatches, undefined);
1773
+ const currentMatches = useStore(router.store, s => s.currentMatches);
1753
1774
  React__namespace.useEffect(router.mount, [router]);
1754
1775
  return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(routerContext.Provider, {
1755
1776
  value: {
@@ -1759,22 +1780,24 @@
1759
1780
  value: [undefined, ...currentMatches]
1760
1781
  }, /*#__PURE__*/React__namespace.createElement(Outlet, null))));
1761
1782
  }
1762
- function useRouter() {
1783
+ function useRouterContext() {
1763
1784
  const value = React__namespace.useContext(routerContext);
1764
1785
  warning(!value, 'useRouter must be used inside a <Router> component!');
1786
+ useStore(value.router.store);
1765
1787
  return value.router;
1766
1788
  }
1767
- function useRouterStore(selector, shallow) {
1768
- const router = useRouter();
1769
- return useStore(router.store, selector, shallow);
1789
+ function useRouter(track, shallow) {
1790
+ const router = useRouterContext();
1791
+ useStore(router.store, track, shallow);
1792
+ return router;
1770
1793
  }
1771
1794
  function useMatches() {
1772
1795
  return React__namespace.useContext(matchesContext);
1773
1796
  }
1774
1797
  function useMatch(opts) {
1775
- const router = useRouter();
1798
+ const router = useRouterContext();
1776
1799
  const nearestMatch = useMatches()[0];
1777
- const match = opts?.from ? router.store.state.currentMatches.find(d => d.route.id === opts?.from) : nearestMatch;
1800
+ const match = opts?.from ? router.state.currentMatches.find(d => d.route.id === opts?.from) : nearestMatch;
1778
1801
  invariant(match, `Could not find ${opts?.from ? `an active match from "${opts.from}"` : 'a nearest match!'}`);
1779
1802
  if (opts?.strict ?? true) {
1780
1803
  invariant(nearestMatch.route.id == match?.route.id, `useMatch("${match?.route.id}") is being called in a component that is meant to render the '${nearestMatch.route.id}' route. Did you mean to 'useMatch("${match?.route.id}", { strict: false })' or 'useRoute("${match?.route.id}")' instead?`);
@@ -1783,26 +1806,26 @@
1783
1806
  return match;
1784
1807
  }
1785
1808
  function useRoute(routeId) {
1786
- const router = useRouter();
1809
+ const router = useRouterContext();
1787
1810
  const resolvedRoute = router.getRoute(routeId);
1788
1811
  invariant(resolvedRoute, `Could not find a route for route "${routeId}"! Did you forget to add it to your route config?`);
1789
1812
  return resolvedRoute;
1790
1813
  }
1791
1814
  function useSearch(opts) {
1792
1815
  const match = useMatch(opts);
1793
- useStore(match.store, d => opts?.track?.(d.search) ?? d.search);
1794
- return match.store.state.search;
1816
+ useStore(match.store, d => opts?.track?.(d.search) ?? d.search, true);
1817
+ return match.state.search;
1795
1818
  }
1796
1819
  function useParams(opts) {
1797
- const router = useRouter();
1820
+ const router = useRouterContext();
1798
1821
  useStore(router.store, d => {
1799
1822
  const params = last(d.currentMatches)?.params;
1800
1823
  return opts?.track?.(params) ?? params;
1801
- });
1802
- return last(router.store.state.currentMatches)?.params;
1824
+ }, true);
1825
+ return last(router.state.currentMatches)?.params;
1803
1826
  }
1804
1827
  function useNavigate(defaultOpts) {
1805
- const router = useRouter();
1828
+ const router = useRouterContext();
1806
1829
  return opts => {
1807
1830
  return router.navigate({
1808
1831
  ...defaultOpts,
@@ -1811,7 +1834,7 @@
1811
1834
  };
1812
1835
  }
1813
1836
  function useMatchRoute() {
1814
- const router = useRouter();
1837
+ const router = useRouterContext();
1815
1838
  return opts => {
1816
1839
  const {
1817
1840
  pending,
@@ -1850,17 +1873,17 @@
1850
1873
  matches,
1851
1874
  match
1852
1875
  }) {
1853
- const router = useRouter();
1854
- useStore(match.store);
1876
+ const router = useRouterContext();
1877
+ useStore(match.store, store => [store.status, store.error], true);
1855
1878
  const defaultPending = React__namespace.useCallback(() => null, []);
1856
1879
  const Inner = React__namespace.useCallback(props => {
1857
- if (props.match.store.state.status === 'error') {
1858
- throw props.match.store.state.error;
1880
+ if (props.match.state.status === 'error') {
1881
+ throw props.match.state.error;
1859
1882
  }
1860
- if (props.match.store.state.status === 'success') {
1883
+ if (props.match.state.status === 'success') {
1861
1884
  return /*#__PURE__*/React__namespace.createElement(props.match.component ?? router.options.defaultComponent ?? Outlet);
1862
1885
  }
1863
- if (props.match.store.state.status === 'pending') {
1886
+ if (props.match.state.status === 'pending') {
1864
1887
  throw props.match.__loadPromise;
1865
1888
  }
1866
1889
  invariant(false, 'Idle routeMatch status encountered during rendering! You should never see this. File an issue!');
@@ -1869,7 +1892,7 @@
1869
1892
  const errorComponent = match.errorComponent ?? router.options.defaultErrorComponent;
1870
1893
  return /*#__PURE__*/React__namespace.createElement(matchesContext.Provider, {
1871
1894
  value: matches
1872
- }, /*#__PURE__*/React__namespace.createElement(React__namespace.Suspense, {
1895
+ }, match.route.options.wrapInSuspense ?? true ? /*#__PURE__*/React__namespace.createElement(React__namespace.Suspense, {
1873
1896
  fallback: /*#__PURE__*/React__namespace.createElement(PendingComponent, null)
1874
1897
  }, /*#__PURE__*/React__namespace.createElement(CatchBoundary, {
1875
1898
  key: match.route.id,
@@ -1877,7 +1900,13 @@
1877
1900
  match: match
1878
1901
  }, /*#__PURE__*/React__namespace.createElement(Inner, {
1879
1902
  match: match
1880
- }))));
1903
+ }))) : /*#__PURE__*/React__namespace.createElement(CatchBoundary, {
1904
+ key: match.route.id,
1905
+ errorComponent: errorComponent,
1906
+ match: match
1907
+ }, /*#__PURE__*/React__namespace.createElement(Inner, {
1908
+ match: match
1909
+ })));
1881
1910
  }
1882
1911
 
1883
1912
  // This is the messiest thing ever... I'm either seriously tired (likely) or
@@ -1906,17 +1935,17 @@
1906
1935
  }
1907
1936
  function CatchBoundaryInner(props) {
1908
1937
  const [activeErrorState, setActiveErrorState] = React__namespace.useState(props.errorState);
1909
- const router = useRouter();
1938
+ const router = useRouterContext();
1910
1939
  const errorComponent = props.errorComponent ?? DefaultErrorBoundary;
1911
1940
  const prevKeyRef = React__namespace.useRef('');
1912
1941
  React__namespace.useEffect(() => {
1913
1942
  if (activeErrorState) {
1914
- if (router.store.state.currentLocation.key !== prevKeyRef.current) {
1943
+ if (router.state.currentLocation.key !== prevKeyRef.current) {
1915
1944
  setActiveErrorState({});
1916
1945
  }
1917
1946
  }
1918
- prevKeyRef.current = router.store.state.currentLocation.key;
1919
- }, [activeErrorState, router.store.state.currentLocation.key]);
1947
+ prevKeyRef.current = router.state.currentLocation.key;
1948
+ }, [activeErrorState, router.state.currentLocation.key]);
1920
1949
  React__namespace.useEffect(() => {
1921
1950
  if (props.errorState.error) {
1922
1951
  setActiveErrorState(props.errorState);
@@ -2030,7 +2059,7 @@
2030
2059
  exports.useParams = useParams;
2031
2060
  exports.useRoute = useRoute;
2032
2061
  exports.useRouter = useRouter;
2033
- exports.useRouterStore = useRouterStore;
2062
+ exports.useRouterContext = useRouterContext;
2034
2063
  exports.useSearch = useSearch;
2035
2064
  exports.useStore = useStore;
2036
2065
  exports.warning = warning;