@remix-run/router 1.11.0-pre.0 → 1.11.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remix-run/router",
3
- "version": "1.11.0-pre.0",
3
+ "version": "1.11.0",
4
4
  "description": "Nested/Data-driven/Framework-agnostic Routing",
5
5
  "keywords": [
6
6
  "remix",
package/router.ts CHANGED
@@ -409,6 +409,7 @@ export interface RouterSubscriber {
409
409
  (
410
410
  state: RouterState,
411
411
  opts: {
412
+ deletedFetchers: string[];
412
413
  unstable_viewTransitionOpts?: ViewTransitionOpts;
413
414
  }
414
415
  ): void;
@@ -887,6 +888,9 @@ export function createRouter(init: RouterInit): Router {
887
888
  // Most recent href/match for fetcher.load calls for fetchers
888
889
  let fetchLoadMatches = new Map<string, FetchLoadMatch>();
889
890
 
891
+ // Ref-count mounted fetchers so we know when it's ok to clean them up
892
+ let activeFetchers = new Map<string, number>();
893
+
890
894
  // Fetchers that have requested a delete when using v7_fetcherPersist,
891
895
  // they'll be officially removed after they return to idle
892
896
  let deletedFetchers = new Set<string>();
@@ -1020,27 +1024,39 @@ export function createRouter(init: RouterInit): Router {
1020
1024
  ...state,
1021
1025
  ...newState,
1022
1026
  };
1023
- subscribers.forEach((subscriber) =>
1024
- subscriber(state, { unstable_viewTransitionOpts: viewTransitionOpts })
1025
- );
1026
1027
 
1027
- // Remove idle fetchers from state since we only care about in-flight fetchers.
1028
+ // Prep fetcher cleanup so we can tell the UI which fetcher data entries
1029
+ // can be removed
1030
+ let completedFetchers: string[] = [];
1031
+ let deletedFetchersKeys: string[] = [];
1032
+
1028
1033
  if (future.v7_fetcherPersist) {
1029
1034
  state.fetchers.forEach((fetcher, key) => {
1030
1035
  if (fetcher.state === "idle") {
1031
1036
  if (deletedFetchers.has(key)) {
1032
- // If the fetcher has unmounted and called router.deleteFetcher(),
1033
- // we can totally delete the fetcher
1034
- deleteFetcher(key);
1037
+ // Unmounted from the UI and can be totally removed
1038
+ deletedFetchersKeys.push(key);
1035
1039
  } else {
1036
- // Otherwise, it must still be mounted in the UI so we just remove
1037
- // it from state now that we've handed off the data to the React
1038
- // layer. Things such as fetchLoadMatches remain for revalidation.
1039
- state.fetchers.delete(key);
1040
+ // Returned to idle but still mounted in the UI, so semi-remains for
1041
+ // revalidations and such
1042
+ completedFetchers.push(key);
1040
1043
  }
1041
1044
  }
1042
1045
  });
1043
1046
  }
1047
+
1048
+ subscribers.forEach((subscriber) =>
1049
+ subscriber(state, {
1050
+ deletedFetchers: deletedFetchersKeys,
1051
+ unstable_viewTransitionOpts: viewTransitionOpts,
1052
+ })
1053
+ );
1054
+
1055
+ // Remove idle fetchers from state since we only care about in-flight fetchers.
1056
+ if (future.v7_fetcherPersist) {
1057
+ completedFetchers.forEach((key) => state.fetchers.delete(key));
1058
+ deletedFetchersKeys.forEach((key) => deleteFetcher(key));
1059
+ }
1044
1060
  }
1045
1061
 
1046
1062
  // Complete a navigation returning the state.navigation back to the IDLE_NAVIGATION
@@ -1749,6 +1765,14 @@ export function createRouter(init: RouterInit): Router {
1749
1765
  }
1750
1766
 
1751
1767
  function getFetcher<TData = any>(key: string): Fetcher<TData> {
1768
+ if (future.v7_fetcherPersist) {
1769
+ activeFetchers.set(key, (activeFetchers.get(key) || 0) + 1);
1770
+ // If this fetcher was previously marked for deletion, unmark it since we
1771
+ // have a new instance
1772
+ if (deletedFetchers.has(key)) {
1773
+ deletedFetchers.delete(key);
1774
+ }
1775
+ }
1752
1776
  return state.fetchers.get(key) || IDLE_FETCHER;
1753
1777
  }
1754
1778
 
@@ -1868,7 +1892,7 @@ export function createRouter(init: RouterInit): Router {
1868
1892
  );
1869
1893
 
1870
1894
  if (fetchRequest.signal.aborted) {
1871
- // We can delete this so long as we weren't aborted by ou our own fetcher
1895
+ // We can delete this so long as we weren't aborted by our own fetcher
1872
1896
  // re-submit which would have put _new_ controller is in fetchControllers
1873
1897
  if (fetchControllers.get(key) === abortController) {
1874
1898
  fetchControllers.delete(key);
@@ -1876,6 +1900,12 @@ export function createRouter(init: RouterInit): Router {
1876
1900
  return;
1877
1901
  }
1878
1902
 
1903
+ if (deletedFetchers.has(key)) {
1904
+ state.fetchers.set(key, getDoneFetcher(undefined));
1905
+ updateState({ fetchers: new Map(state.fetchers) });
1906
+ return;
1907
+ }
1908
+
1879
1909
  if (isRedirectResult(actionResult)) {
1880
1910
  fetchControllers.delete(key);
1881
1911
  if (pendingNavigationLoadId > originatingLoadId) {
@@ -2127,6 +2157,12 @@ export function createRouter(init: RouterInit): Router {
2127
2157
  return;
2128
2158
  }
2129
2159
 
2160
+ if (deletedFetchers.has(key)) {
2161
+ state.fetchers.set(key, getDoneFetcher(undefined));
2162
+ updateState({ fetchers: new Map(state.fetchers) });
2163
+ return;
2164
+ }
2165
+
2130
2166
  // If the loader threw a redirect Response, start a new REPLACE navigation
2131
2167
  if (isRedirectResult(result)) {
2132
2168
  if (pendingNavigationLoadId > originatingLoadId) {
@@ -2145,17 +2181,7 @@ export function createRouter(init: RouterInit): Router {
2145
2181
 
2146
2182
  // Process any non-redirect errors thrown
2147
2183
  if (isErrorResult(result)) {
2148
- let boundaryMatch = findNearestBoundary(state.matches, routeId);
2149
- state.fetchers.delete(key);
2150
- // TODO: In remix, this would reset to IDLE_NAVIGATION if it was a catch -
2151
- // do we need to behave any differently with our non-redirect errors?
2152
- // What if it was a non-redirect Response?
2153
- updateState({
2154
- fetchers: new Map(state.fetchers),
2155
- errors: {
2156
- [boundaryMatch.route.id]: result.error,
2157
- },
2158
- });
2184
+ setFetcherError(key, routeId, result.error);
2159
2185
  return;
2160
2186
  }
2161
2187
 
@@ -2404,7 +2430,13 @@ export function createRouter(init: RouterInit): Router {
2404
2430
 
2405
2431
  function deleteFetcherAndUpdateState(key: string): void {
2406
2432
  if (future.v7_fetcherPersist) {
2407
- deletedFetchers.add(key);
2433
+ let count = (activeFetchers.get(key) || 0) - 1;
2434
+ if (count <= 0) {
2435
+ activeFetchers.delete(key);
2436
+ deletedFetchers.add(key);
2437
+ } else {
2438
+ activeFetchers.set(key, count);
2439
+ }
2408
2440
  } else {
2409
2441
  deleteFetcher(key);
2410
2442
  }