@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/dist/router.d.ts CHANGED
@@ -304,6 +304,7 @@ type ViewTransitionOpts = {
304
304
  */
305
305
  export interface RouterSubscriber {
306
306
  (state: RouterState, opts: {
307
+ deletedFetchers: string[];
307
308
  unstable_viewTransitionOpts?: ViewTransitionOpts;
308
309
  }): void;
309
310
  }
package/dist/router.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @remix-run/router v1.11.0-pre.0
2
+ * @remix-run/router v1.11.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1418,6 +1418,8 @@ function createRouter(init) {
1418
1418
  let fetchRedirectIds = new Set();
1419
1419
  // Most recent href/match for fetcher.load calls for fetchers
1420
1420
  let fetchLoadMatches = new Map();
1421
+ // Ref-count mounted fetchers so we know when it's ok to clean them up
1422
+ let activeFetchers = new Map();
1421
1423
  // Fetchers that have requested a delete when using v7_fetcherPersist,
1422
1424
  // they'll be officially removed after they return to idle
1423
1425
  let deletedFetchers = new Set();
@@ -1525,26 +1527,33 @@ function createRouter(init) {
1525
1527
  // Update our state and notify the calling context of the change
1526
1528
  function updateState(newState, viewTransitionOpts) {
1527
1529
  state = _extends({}, state, newState);
1528
- subscribers.forEach(subscriber => subscriber(state, {
1529
- unstable_viewTransitionOpts: viewTransitionOpts
1530
- }));
1531
- // Remove idle fetchers from state since we only care about in-flight fetchers.
1530
+ // Prep fetcher cleanup so we can tell the UI which fetcher data entries
1531
+ // can be removed
1532
+ let completedFetchers = [];
1533
+ let deletedFetchersKeys = [];
1532
1534
  if (future.v7_fetcherPersist) {
1533
1535
  state.fetchers.forEach((fetcher, key) => {
1534
1536
  if (fetcher.state === "idle") {
1535
1537
  if (deletedFetchers.has(key)) {
1536
- // If the fetcher has unmounted and called router.deleteFetcher(),
1537
- // we can totally delete the fetcher
1538
- deleteFetcher(key);
1538
+ // Unmounted from the UI and can be totally removed
1539
+ deletedFetchersKeys.push(key);
1539
1540
  } else {
1540
- // Otherwise, it must still be mounted in the UI so we just remove
1541
- // it from state now that we've handed off the data to the React
1542
- // layer. Things such as fetchLoadMatches remain for revalidation.
1543
- state.fetchers.delete(key);
1541
+ // Returned to idle but still mounted in the UI, so semi-remains for
1542
+ // revalidations and such
1543
+ completedFetchers.push(key);
1544
1544
  }
1545
1545
  }
1546
1546
  });
1547
1547
  }
1548
+ subscribers.forEach(subscriber => subscriber(state, {
1549
+ deletedFetchers: deletedFetchersKeys,
1550
+ unstable_viewTransitionOpts: viewTransitionOpts
1551
+ }));
1552
+ // Remove idle fetchers from state since we only care about in-flight fetchers.
1553
+ if (future.v7_fetcherPersist) {
1554
+ completedFetchers.forEach(key => state.fetchers.delete(key));
1555
+ deletedFetchersKeys.forEach(key => deleteFetcher(key));
1556
+ }
1548
1557
  }
1549
1558
  // Complete a navigation returning the state.navigation back to the IDLE_NAVIGATION
1550
1559
  // and setting state.[historyAction/location/matches] to the new route.
@@ -2062,6 +2071,14 @@ function createRouter(init) {
2062
2071
  } : {});
2063
2072
  }
2064
2073
  function getFetcher(key) {
2074
+ if (future.v7_fetcherPersist) {
2075
+ activeFetchers.set(key, (activeFetchers.get(key) || 0) + 1);
2076
+ // If this fetcher was previously marked for deletion, unmark it since we
2077
+ // have a new instance
2078
+ if (deletedFetchers.has(key)) {
2079
+ deletedFetchers.delete(key);
2080
+ }
2081
+ }
2065
2082
  return state.fetchers.get(key) || IDLE_FETCHER;
2066
2083
  }
2067
2084
  // Trigger a fetcher load/submit for the given fetcher key
@@ -2130,13 +2147,20 @@ function createRouter(init) {
2130
2147
  let originatingLoadId = incrementingLoadId;
2131
2148
  let actionResult = await callLoaderOrAction("action", fetchRequest, match, requestMatches, manifest, mapRouteProperties, basename);
2132
2149
  if (fetchRequest.signal.aborted) {
2133
- // We can delete this so long as we weren't aborted by ou our own fetcher
2150
+ // We can delete this so long as we weren't aborted by our own fetcher
2134
2151
  // re-submit which would have put _new_ controller is in fetchControllers
2135
2152
  if (fetchControllers.get(key) === abortController) {
2136
2153
  fetchControllers.delete(key);
2137
2154
  }
2138
2155
  return;
2139
2156
  }
2157
+ if (deletedFetchers.has(key)) {
2158
+ state.fetchers.set(key, getDoneFetcher(undefined));
2159
+ updateState({
2160
+ fetchers: new Map(state.fetchers)
2161
+ });
2162
+ return;
2163
+ }
2140
2164
  if (isRedirectResult(actionResult)) {
2141
2165
  fetchControllers.delete(key);
2142
2166
  if (pendingNavigationLoadId > originatingLoadId) {
@@ -2296,6 +2320,13 @@ function createRouter(init) {
2296
2320
  if (fetchRequest.signal.aborted) {
2297
2321
  return;
2298
2322
  }
2323
+ if (deletedFetchers.has(key)) {
2324
+ state.fetchers.set(key, getDoneFetcher(undefined));
2325
+ updateState({
2326
+ fetchers: new Map(state.fetchers)
2327
+ });
2328
+ return;
2329
+ }
2299
2330
  // If the loader threw a redirect Response, start a new REPLACE navigation
2300
2331
  if (isRedirectResult(result)) {
2301
2332
  if (pendingNavigationLoadId > originatingLoadId) {
@@ -2315,17 +2346,7 @@ function createRouter(init) {
2315
2346
  }
2316
2347
  // Process any non-redirect errors thrown
2317
2348
  if (isErrorResult(result)) {
2318
- let boundaryMatch = findNearestBoundary(state.matches, routeId);
2319
- state.fetchers.delete(key);
2320
- // TODO: In remix, this would reset to IDLE_NAVIGATION if it was a catch -
2321
- // do we need to behave any differently with our non-redirect errors?
2322
- // What if it was a non-redirect Response?
2323
- updateState({
2324
- fetchers: new Map(state.fetchers),
2325
- errors: {
2326
- [boundaryMatch.route.id]: result.error
2327
- }
2328
- });
2349
+ setFetcherError(key, routeId, result.error);
2329
2350
  return;
2330
2351
  }
2331
2352
  invariant(!isDeferredResult(result), "Unhandled fetcher deferred data");
@@ -2495,7 +2516,13 @@ function createRouter(init) {
2495
2516
  }
2496
2517
  function deleteFetcherAndUpdateState(key) {
2497
2518
  if (future.v7_fetcherPersist) {
2498
- deletedFetchers.add(key);
2519
+ let count = (activeFetchers.get(key) || 0) - 1;
2520
+ if (count <= 0) {
2521
+ activeFetchers.delete(key);
2522
+ deletedFetchers.add(key);
2523
+ } else {
2524
+ activeFetchers.set(key, count);
2525
+ }
2499
2526
  } else {
2500
2527
  deleteFetcher(key);
2501
2528
  }