@remix-run/router 1.3.0 → 1.3.1
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/CHANGELOG.md +14 -0
- package/dist/history.d.ts +1 -1
- package/dist/router.cjs.js +121 -117
- package/dist/router.cjs.js.map +1 -1
- package/dist/router.js +121 -117
- package/dist/router.js.map +1 -1
- package/dist/router.umd.js +121 -117
- package/dist/router.umd.js.map +1 -1
- package/dist/router.umd.min.js +2 -2
- package/dist/router.umd.min.js.map +1 -1
- package/dist/utils.d.ts +2 -2
- package/history.ts +6 -22
- package/package.json +1 -1
- package/router.ts +133 -135
- package/utils.ts +14 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# `@remix-run/router`
|
|
2
2
|
|
|
3
|
+
## 1.3.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Fixes 2 separate issues for revalidating fetcher `shouldRevalidate` calls ([#9948](https://github.com/remix-run/react-router/pull/9948))
|
|
8
|
+
- The `shouldRevalidate` function was only being called for _explicit_ revalidation scenarios (after a mutation, manual `useRevalidator` call, or an `X-Remix-Revalidate` header used for cookie setting in Remix). It was not properly being called on _implicit_ revalidation scenarios that also apply to navigation `loader` revalidation, such as a change in search params or clicking a link for the page we're already on. It's now correctly called in those additional scenarios.
|
|
9
|
+
- The parameters being passed were incorrect and inconsistent with one another since the `current*`/`next*` parameters reflected the static `fetcher.load` URL (and thus were identical). Instead, they should have reflected the the navigation that triggered the revalidation (as the `form*` parameters did). These parameters now correctly reflect the triggering navigation.
|
|
10
|
+
- Respect `preventScrollReset` on `<fetcher.Form>` ([#9963](https://github.com/remix-run/react-router/pull/9963))
|
|
11
|
+
- Do not short circuit on hash change only mutation submissions ([#9944](https://github.com/remix-run/react-router/pull/9944))
|
|
12
|
+
- Remove `instanceof` check from `isRouteErrorResponse` to avoid bundling issues on the server ([#9930](https://github.com/remix-run/react-router/pull/9930))
|
|
13
|
+
- Fix navigation for hash routers on manual URL changes ([#9980](https://github.com/remix-run/react-router/pull/9980))
|
|
14
|
+
- Detect when a `defer` call only contains critical data and remove the `AbortController` ([#9965](https://github.com/remix-run/react-router/pull/9965))
|
|
15
|
+
- Send the name as the value when url-encoding `File` `FormData` entries ([#9867](https://github.com/remix-run/react-router/pull/9867))
|
|
16
|
+
|
|
3
17
|
## 1.3.0
|
|
4
18
|
|
|
5
19
|
### Minor Changes
|
package/dist/history.d.ts
CHANGED
package/dist/router.cjs.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @remix-run/router v1.3.
|
|
2
|
+
* @remix-run/router v1.3.1
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -433,26 +433,17 @@ function getUrlBasedHistory(getLocation, createHref, validateLocation, options)
|
|
|
433
433
|
}
|
|
434
434
|
|
|
435
435
|
function handlePop() {
|
|
436
|
-
|
|
436
|
+
action = exports.Action.Pop;
|
|
437
437
|
let nextIndex = getIndex();
|
|
438
|
+
let delta = nextIndex == null ? null : nextIndex - index;
|
|
439
|
+
index = nextIndex;
|
|
438
440
|
|
|
439
|
-
if (
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
listener({
|
|
446
|
-
action,
|
|
447
|
-
location: history.location,
|
|
448
|
-
delta
|
|
449
|
-
});
|
|
450
|
-
}
|
|
451
|
-
} else {
|
|
452
|
-
warning$1(false, // TODO: Write up a doc that explains our blocking strategy in detail
|
|
453
|
-
// and link to it here so people can understand better what is going on
|
|
454
|
-
// and how to avoid it.
|
|
455
|
-
"You are trying to block a POP navigation to a location that was not " + "created by @remix-run/router. The block will fail silently in " + "production, but in general you should do all navigation with the " + "router (instead of using window.history.pushState directly) " + "to avoid this situation.");
|
|
441
|
+
if (listener) {
|
|
442
|
+
listener({
|
|
443
|
+
action,
|
|
444
|
+
location: history.location,
|
|
445
|
+
delta
|
|
446
|
+
});
|
|
456
447
|
}
|
|
457
448
|
}
|
|
458
449
|
|
|
@@ -1250,6 +1241,12 @@ class DeferredData {
|
|
|
1250
1241
|
[key]: this.trackPromise(key, value)
|
|
1251
1242
|
});
|
|
1252
1243
|
}, {});
|
|
1244
|
+
|
|
1245
|
+
if (this.done) {
|
|
1246
|
+
// All incoming values were resolved
|
|
1247
|
+
this.unlistenAbortSignal();
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1253
1250
|
this.init = responseInit;
|
|
1254
1251
|
}
|
|
1255
1252
|
|
|
@@ -1437,11 +1434,11 @@ class ErrorResponse {
|
|
|
1437
1434
|
}
|
|
1438
1435
|
/**
|
|
1439
1436
|
* Check if the given error is an ErrorResponse generated from a 4xx/5xx
|
|
1440
|
-
* Response
|
|
1437
|
+
* Response thrown from an action/loader
|
|
1441
1438
|
*/
|
|
1442
1439
|
|
|
1443
|
-
function isRouteErrorResponse(
|
|
1444
|
-
return
|
|
1440
|
+
function isRouteErrorResponse(error) {
|
|
1441
|
+
return error != null && typeof error.status === "number" && typeof error.statusText === "string" && typeof error.internal === "boolean" && "data" in error;
|
|
1445
1442
|
}
|
|
1446
1443
|
|
|
1447
1444
|
//#region Types and Constants
|
|
@@ -1616,13 +1613,14 @@ function createRouter(init) {
|
|
|
1616
1613
|
return;
|
|
1617
1614
|
}
|
|
1618
1615
|
|
|
1616
|
+
warning(activeBlocker != null && delta === null, "You are trying to use a blocker on a POP navigation to a location " + "that was not created by @remix-run/router. This will fail silently in " + "production. This can happen if you are navigating outside the router " + "via `window.history.pushState`/`window.location.hash` instead of using " + "router navigation APIs. This can also happen if you are using " + "createHashRouter and the user manually changes the URL.");
|
|
1619
1617
|
let blockerKey = shouldBlockNavigation({
|
|
1620
1618
|
currentLocation: state.location,
|
|
1621
1619
|
nextLocation: location,
|
|
1622
1620
|
historyAction
|
|
1623
1621
|
});
|
|
1624
1622
|
|
|
1625
|
-
if (blockerKey) {
|
|
1623
|
+
if (blockerKey && delta != null) {
|
|
1626
1624
|
// Restore the URL to match the current UI, but don't update router state
|
|
1627
1625
|
ignoreNextHistoryUpdate = true;
|
|
1628
1626
|
init.history.go(delta * -1); // Put the blocker into a blocked state
|
|
@@ -1905,10 +1903,12 @@ function createRouter(init) {
|
|
|
1905
1903
|
}
|
|
1906
1904
|
});
|
|
1907
1905
|
return;
|
|
1908
|
-
} // Short circuit if it's only a hash change
|
|
1906
|
+
} // Short circuit if it's only a hash change and not a mutation submission
|
|
1907
|
+
// For example, on /page#hash and submit a <Form method="post"> which will
|
|
1908
|
+
// default to a navigation to /page
|
|
1909
1909
|
|
|
1910
1910
|
|
|
1911
|
-
if (isHashChangeOnly(state.location, location)) {
|
|
1911
|
+
if (isHashChangeOnly(state.location, location) && !(opts && opts.submission && isMutationMethod(opts.submission.formMethod))) {
|
|
1912
1912
|
completeNavigation(location, {
|
|
1913
1913
|
matches
|
|
1914
1914
|
});
|
|
@@ -2122,9 +2122,8 @@ function createRouter(init) {
|
|
|
2122
2122
|
|
|
2123
2123
|
|
|
2124
2124
|
if (!isUninterruptedRevalidation) {
|
|
2125
|
-
revalidatingFetchers.forEach(
|
|
2126
|
-
let
|
|
2127
|
-
let fetcher = state.fetchers.get(key);
|
|
2125
|
+
revalidatingFetchers.forEach(rf => {
|
|
2126
|
+
let fetcher = state.fetchers.get(rf.key);
|
|
2128
2127
|
let revalidatingFetcher = {
|
|
2129
2128
|
state: "loading",
|
|
2130
2129
|
data: fetcher && fetcher.data,
|
|
@@ -2134,7 +2133,7 @@ function createRouter(init) {
|
|
|
2134
2133
|
formData: undefined,
|
|
2135
2134
|
" _hasFetcherDoneAnything ": true
|
|
2136
2135
|
};
|
|
2137
|
-
state.fetchers.set(key, revalidatingFetcher);
|
|
2136
|
+
state.fetchers.set(rf.key, revalidatingFetcher);
|
|
2138
2137
|
});
|
|
2139
2138
|
let actionData = pendingActionData || state.actionData;
|
|
2140
2139
|
updateState(_extends({
|
|
@@ -2149,10 +2148,7 @@ function createRouter(init) {
|
|
|
2149
2148
|
}
|
|
2150
2149
|
|
|
2151
2150
|
pendingNavigationLoadId = ++incrementingLoadId;
|
|
2152
|
-
revalidatingFetchers.forEach(
|
|
2153
|
-
let [key] = _ref3;
|
|
2154
|
-
return fetchControllers.set(key, pendingNavigationController);
|
|
2155
|
-
});
|
|
2151
|
+
revalidatingFetchers.forEach(rf => fetchControllers.set(rf.key, pendingNavigationController));
|
|
2156
2152
|
let {
|
|
2157
2153
|
results,
|
|
2158
2154
|
loaderResults,
|
|
@@ -2168,10 +2164,7 @@ function createRouter(init) {
|
|
|
2168
2164
|
// reassigned to new controllers for the next navigation
|
|
2169
2165
|
|
|
2170
2166
|
|
|
2171
|
-
revalidatingFetchers.forEach(
|
|
2172
|
-
let [key] = _ref4;
|
|
2173
|
-
return fetchControllers.delete(key);
|
|
2174
|
-
}); // If any loaders returned a redirect Response, start a new REPLACE navigation
|
|
2167
|
+
revalidatingFetchers.forEach(rf => fetchControllers.delete(rf.key)); // If any loaders returned a redirect Response, start a new REPLACE navigation
|
|
2175
2168
|
|
|
2176
2169
|
let redirect = findRedirect(results);
|
|
2177
2170
|
|
|
@@ -2235,6 +2228,7 @@ function createRouter(init) {
|
|
|
2235
2228
|
submission
|
|
2236
2229
|
} = normalizeNavigateOptions(href, opts, true);
|
|
2237
2230
|
let match = getTargetMatch(matches, path);
|
|
2231
|
+
pendingPreventScrollReset = (opts && opts.preventScrollReset) === true;
|
|
2238
2232
|
|
|
2239
2233
|
if (submission && isMutationMethod(submission.formMethod)) {
|
|
2240
2234
|
handleFetcherAction(key, routeId, path, match, matches, submission);
|
|
@@ -2243,7 +2237,12 @@ function createRouter(init) {
|
|
|
2243
2237
|
// revalidations
|
|
2244
2238
|
|
|
2245
2239
|
|
|
2246
|
-
fetchLoadMatches.set(key,
|
|
2240
|
+
fetchLoadMatches.set(key, {
|
|
2241
|
+
routeId,
|
|
2242
|
+
path,
|
|
2243
|
+
match,
|
|
2244
|
+
matches
|
|
2245
|
+
});
|
|
2247
2246
|
handleFetcherLoader(key, routeId, path, match, matches, submission);
|
|
2248
2247
|
} // Call the action for the matched fetcher.submit(), and then handle redirects,
|
|
2249
2248
|
// errors, and revalidation
|
|
@@ -2349,11 +2348,8 @@ function createRouter(init) {
|
|
|
2349
2348
|
// current fetcher which we want to keep in it's current loading state which
|
|
2350
2349
|
// contains it's action submission info + action data
|
|
2351
2350
|
|
|
2352
|
-
revalidatingFetchers.filter(
|
|
2353
|
-
let
|
|
2354
|
-
return staleKey !== key;
|
|
2355
|
-
}).forEach(_ref6 => {
|
|
2356
|
-
let [staleKey] = _ref6;
|
|
2351
|
+
revalidatingFetchers.filter(rf => rf.key !== key).forEach(rf => {
|
|
2352
|
+
let staleKey = rf.key;
|
|
2357
2353
|
let existingFetcher = state.fetchers.get(staleKey);
|
|
2358
2354
|
let revalidatingFetcher = {
|
|
2359
2355
|
state: "loading",
|
|
@@ -2382,10 +2378,7 @@ function createRouter(init) {
|
|
|
2382
2378
|
|
|
2383
2379
|
fetchReloadIds.delete(key);
|
|
2384
2380
|
fetchControllers.delete(key);
|
|
2385
|
-
revalidatingFetchers.forEach(
|
|
2386
|
-
let [staleKey] = _ref7;
|
|
2387
|
-
return fetchControllers.delete(staleKey);
|
|
2388
|
-
});
|
|
2381
|
+
revalidatingFetchers.forEach(r => fetchControllers.delete(r.key));
|
|
2389
2382
|
let redirect = findRedirect(results);
|
|
2390
2383
|
|
|
2391
2384
|
if (redirect) {
|
|
@@ -2625,16 +2618,10 @@ function createRouter(init) {
|
|
|
2625
2618
|
// Call all navigation loaders and revalidating fetcher loaders in parallel,
|
|
2626
2619
|
// then slice off the results into separate arrays so we can handle them
|
|
2627
2620
|
// accordingly
|
|
2628
|
-
let results = await Promise.all([...matchesToLoad.map(match => callLoaderOrAction("loader", request, match, matches, router.basename)), ...fetchersToLoad.map(
|
|
2629
|
-
let [, href, match, fetchMatches] = _ref8;
|
|
2630
|
-
return callLoaderOrAction("loader", createClientSideRequest(init.history, href, request.signal), match, fetchMatches, router.basename);
|
|
2631
|
-
})]);
|
|
2621
|
+
let results = await Promise.all([...matchesToLoad.map(match => callLoaderOrAction("loader", request, match, matches, router.basename)), ...fetchersToLoad.map(f => callLoaderOrAction("loader", createClientSideRequest(init.history, f.path, request.signal), f.match, f.matches, router.basename))]);
|
|
2632
2622
|
let loaderResults = results.slice(0, matchesToLoad.length);
|
|
2633
2623
|
let fetcherResults = results.slice(matchesToLoad.length);
|
|
2634
|
-
await Promise.all([resolveDeferredResults(currentMatches, matchesToLoad, loaderResults, request.signal, false, state.loaderData), resolveDeferredResults(currentMatches, fetchersToLoad.map(
|
|
2635
|
-
let [,, match] = _ref9;
|
|
2636
|
-
return match;
|
|
2637
|
-
}), fetcherResults, request.signal, true)]);
|
|
2624
|
+
await Promise.all([resolveDeferredResults(currentMatches, matchesToLoad, loaderResults, request.signal, false, state.loaderData), resolveDeferredResults(currentMatches, fetchersToLoad.map(f => f.match), fetcherResults, request.signal, true)]);
|
|
2638
2625
|
return {
|
|
2639
2626
|
results,
|
|
2640
2627
|
loaderResults,
|
|
@@ -2773,12 +2760,12 @@ function createRouter(init) {
|
|
|
2773
2760
|
});
|
|
2774
2761
|
}
|
|
2775
2762
|
|
|
2776
|
-
function shouldBlockNavigation(
|
|
2763
|
+
function shouldBlockNavigation(_ref2) {
|
|
2777
2764
|
let {
|
|
2778
2765
|
currentLocation,
|
|
2779
2766
|
nextLocation,
|
|
2780
2767
|
historyAction
|
|
2781
|
-
} =
|
|
2768
|
+
} = _ref2;
|
|
2782
2769
|
|
|
2783
2770
|
if (activeBlocker == null) {
|
|
2784
2771
|
return;
|
|
@@ -3372,24 +3359,15 @@ function normalizeNavigateOptions(to, opts, isFetcher) {
|
|
|
3372
3359
|
|
|
3373
3360
|
|
|
3374
3361
|
let parsedPath = parsePath(path);
|
|
3362
|
+
let searchParams = convertFormDataToSearchParams(opts.formData); // Since fetcher GET submissions only run a single loader (as opposed to
|
|
3363
|
+
// navigation GET submissions which run all loaders), we need to preserve
|
|
3364
|
+
// any incoming ?index params
|
|
3375
3365
|
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
// navigation GET submissions which run all loaders), we need to preserve
|
|
3379
|
-
// any incoming ?index params
|
|
3380
|
-
|
|
3381
|
-
if (isFetcher && parsedPath.search && hasNakedIndexQuery(parsedPath.search)) {
|
|
3382
|
-
searchParams.append("index", "");
|
|
3383
|
-
}
|
|
3384
|
-
|
|
3385
|
-
parsedPath.search = "?" + searchParams;
|
|
3386
|
-
} catch (e) {
|
|
3387
|
-
return {
|
|
3388
|
-
path,
|
|
3389
|
-
error: getInternalRouterError(400)
|
|
3390
|
-
};
|
|
3366
|
+
if (isFetcher && parsedPath.search && hasNakedIndexQuery(parsedPath.search)) {
|
|
3367
|
+
searchParams.append("index", "");
|
|
3391
3368
|
}
|
|
3392
3369
|
|
|
3370
|
+
parsedPath.search = "?" + searchParams;
|
|
3393
3371
|
return {
|
|
3394
3372
|
path: createPath(parsedPath),
|
|
3395
3373
|
submission
|
|
@@ -3413,25 +3391,73 @@ function getLoaderMatchesUntilBoundary(matches, boundaryId) {
|
|
|
3413
3391
|
}
|
|
3414
3392
|
|
|
3415
3393
|
function getMatchesToLoad(history, state, matches, submission, location, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, pendingActionData, pendingError, fetchLoadMatches) {
|
|
3416
|
-
let actionResult = pendingError ? Object.values(pendingError)[0] : pendingActionData ? Object.values(pendingActionData)[0] : undefined;
|
|
3394
|
+
let actionResult = pendingError ? Object.values(pendingError)[0] : pendingActionData ? Object.values(pendingActionData)[0] : undefined;
|
|
3395
|
+
let currentUrl = history.createURL(state.location);
|
|
3396
|
+
let nextUrl = history.createURL(location);
|
|
3397
|
+
let defaultShouldRevalidate = // Forced revalidation due to submission, useRevalidate, or X-Remix-Revalidate
|
|
3398
|
+
isRevalidationRequired || // Clicked the same link, resubmitted a GET form
|
|
3399
|
+
currentUrl.toString() === nextUrl.toString() || // Search params affect all loaders
|
|
3400
|
+
currentUrl.search !== nextUrl.search; // Pick navigation matches that are net-new or qualify for revalidation
|
|
3417
3401
|
|
|
3418
3402
|
let boundaryId = pendingError ? Object.keys(pendingError)[0] : undefined;
|
|
3419
3403
|
let boundaryMatches = getLoaderMatchesUntilBoundary(matches, boundaryId);
|
|
3420
|
-
let navigationMatches = boundaryMatches.filter((match, index) =>
|
|
3421
|
-
|
|
3404
|
+
let navigationMatches = boundaryMatches.filter((match, index) => {
|
|
3405
|
+
if (match.route.loader == null) {
|
|
3406
|
+
return false;
|
|
3407
|
+
} // Always call the loader on new route instances and pending defer cancellations
|
|
3422
3408
|
|
|
3423
|
-
let revalidatingFetchers = [];
|
|
3424
|
-
fetchLoadMatches && fetchLoadMatches.forEach((_ref11, key) => {
|
|
3425
|
-
let [href, match, fetchMatches] = _ref11;
|
|
3426
3409
|
|
|
3427
|
-
|
|
3428
|
-
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
|
|
3410
|
+
if (isNewLoader(state.loaderData, state.matches[index], match) || cancelledDeferredRoutes.some(id => id === match.route.id)) {
|
|
3411
|
+
return true;
|
|
3412
|
+
} // This is the default implementation for when we revalidate. If the route
|
|
3413
|
+
// provides it's own implementation, then we give them full control but
|
|
3414
|
+
// provide this value so they can leverage it if needed after they check
|
|
3415
|
+
// their own specific use cases
|
|
3416
|
+
|
|
3417
|
+
|
|
3418
|
+
let currentRouteMatch = state.matches[index];
|
|
3419
|
+
let nextRouteMatch = match;
|
|
3420
|
+
return shouldRevalidateLoader(match, _extends({
|
|
3421
|
+
currentUrl,
|
|
3422
|
+
currentParams: currentRouteMatch.params,
|
|
3423
|
+
nextUrl,
|
|
3424
|
+
nextParams: nextRouteMatch.params
|
|
3425
|
+
}, submission, {
|
|
3426
|
+
actionResult,
|
|
3427
|
+
defaultShouldRevalidate: defaultShouldRevalidate || isNewRouteInstance(currentRouteMatch, nextRouteMatch)
|
|
3428
|
+
}));
|
|
3429
|
+
}); // Pick fetcher.loads that need to be revalidated
|
|
3430
|
+
|
|
3431
|
+
let revalidatingFetchers = [];
|
|
3432
|
+
fetchLoadMatches && fetchLoadMatches.forEach((f, key) => {
|
|
3433
|
+
if (!matches.some(m => m.route.id === f.routeId)) {
|
|
3434
|
+
// This fetcher is not going to be present in the subsequent render so
|
|
3435
|
+
// there's no need to revalidate it
|
|
3436
|
+
return;
|
|
3437
|
+
} else if (cancelledFetcherLoads.includes(key)) {
|
|
3438
|
+
// This fetcher was cancelled from a prior action submission - force reload
|
|
3439
|
+
revalidatingFetchers.push(_extends({
|
|
3440
|
+
key
|
|
3441
|
+
}, f));
|
|
3442
|
+
} else {
|
|
3443
|
+
// Revalidating fetchers are decoupled from the route matches since they
|
|
3444
|
+
// hit a static href, so they _always_ check shouldRevalidate and the
|
|
3445
|
+
// default is strictly if a revalidation is explicitly required (action
|
|
3446
|
+
// submissions, useRevalidator, X-Remix-Revalidate).
|
|
3447
|
+
let shouldRevalidate = shouldRevalidateLoader(f.match, _extends({
|
|
3448
|
+
currentUrl,
|
|
3449
|
+
currentParams: state.matches[state.matches.length - 1].params,
|
|
3450
|
+
nextUrl,
|
|
3451
|
+
nextParams: matches[matches.length - 1].params
|
|
3452
|
+
}, submission, {
|
|
3453
|
+
actionResult,
|
|
3454
|
+
defaultShouldRevalidate
|
|
3455
|
+
}));
|
|
3432
3456
|
|
|
3433
3457
|
if (shouldRevalidate) {
|
|
3434
|
-
revalidatingFetchers.push(
|
|
3458
|
+
revalidatingFetchers.push(_extends({
|
|
3459
|
+
key
|
|
3460
|
+
}, f));
|
|
3435
3461
|
}
|
|
3436
3462
|
}
|
|
3437
3463
|
});
|
|
@@ -3454,43 +3480,20 @@ function isNewRouteInstance(currentMatch, match) {
|
|
|
3454
3480
|
return (// param change for this match, /users/123 -> /users/456
|
|
3455
3481
|
currentMatch.pathname !== match.pathname || // splat param changed, which is not present in match.path
|
|
3456
3482
|
// e.g. /files/images/avatar.jpg -> files/finances.xls
|
|
3457
|
-
currentPath && currentPath.endsWith("*") && currentMatch.params["*"] !== match.params["*"]
|
|
3483
|
+
currentPath != null && currentPath.endsWith("*") && currentMatch.params["*"] !== match.params["*"]
|
|
3458
3484
|
);
|
|
3459
3485
|
}
|
|
3460
3486
|
|
|
3461
|
-
function shouldRevalidateLoader(
|
|
3462
|
-
|
|
3463
|
-
|
|
3464
|
-
let nextUrl = history.createURL(location);
|
|
3465
|
-
let nextParams = match.params; // This is the default implementation as to when we revalidate. If the route
|
|
3466
|
-
// provides it's own implementation, then we give them full control but
|
|
3467
|
-
// provide this value so they can leverage it if needed after they check
|
|
3468
|
-
// their own specific use cases
|
|
3469
|
-
// Note that fetchers always provide the same current/next locations so the
|
|
3470
|
-
// URL-based checks here don't apply to fetcher shouldRevalidate calls
|
|
3471
|
-
|
|
3472
|
-
let defaultShouldRevalidate = isNewRouteInstance(currentMatch, match) || // Clicked the same link, resubmitted a GET form
|
|
3473
|
-
currentUrl.toString() === nextUrl.toString() || // Search params affect all loaders
|
|
3474
|
-
currentUrl.search !== nextUrl.search || // Forced revalidation due to submission, useRevalidate, or X-Remix-Revalidate
|
|
3475
|
-
isRevalidationRequired;
|
|
3476
|
-
|
|
3477
|
-
if (match.route.shouldRevalidate) {
|
|
3478
|
-
let routeChoice = match.route.shouldRevalidate(_extends({
|
|
3479
|
-
currentUrl,
|
|
3480
|
-
currentParams,
|
|
3481
|
-
nextUrl,
|
|
3482
|
-
nextParams
|
|
3483
|
-
}, submission, {
|
|
3484
|
-
actionResult,
|
|
3485
|
-
defaultShouldRevalidate
|
|
3486
|
-
}));
|
|
3487
|
+
function shouldRevalidateLoader(loaderMatch, arg) {
|
|
3488
|
+
if (loaderMatch.route.shouldRevalidate) {
|
|
3489
|
+
let routeChoice = loaderMatch.route.shouldRevalidate(arg);
|
|
3487
3490
|
|
|
3488
3491
|
if (typeof routeChoice === "boolean") {
|
|
3489
3492
|
return routeChoice;
|
|
3490
3493
|
}
|
|
3491
3494
|
}
|
|
3492
3495
|
|
|
3493
|
-
return defaultShouldRevalidate;
|
|
3496
|
+
return arg.defaultShouldRevalidate;
|
|
3494
3497
|
}
|
|
3495
3498
|
|
|
3496
3499
|
async function callLoaderOrAction(type, request, match, matches, basename, isStaticRequest, isRouteRequest, requestContext) {
|
|
@@ -3665,8 +3668,8 @@ function convertFormDataToSearchParams(formData) {
|
|
|
3665
3668
|
let searchParams = new URLSearchParams();
|
|
3666
3669
|
|
|
3667
3670
|
for (let [key, value] of formData.entries()) {
|
|
3668
|
-
|
|
3669
|
-
searchParams.append(key, value);
|
|
3671
|
+
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#converting-an-entry-list-to-a-list-of-name-value-pairs
|
|
3672
|
+
searchParams.append(key, value instanceof File ? value.name : value);
|
|
3670
3673
|
}
|
|
3671
3674
|
|
|
3672
3675
|
return searchParams;
|
|
@@ -3757,7 +3760,10 @@ function processLoaderData(state, matches, matchesToLoad, results, pendingError,
|
|
|
3757
3760
|
} = processRouteLoaderData(matches, matchesToLoad, results, pendingError, activeDeferreds); // Process results from our revalidating fetchers
|
|
3758
3761
|
|
|
3759
3762
|
for (let index = 0; index < revalidatingFetchers.length; index++) {
|
|
3760
|
-
let
|
|
3763
|
+
let {
|
|
3764
|
+
key,
|
|
3765
|
+
match
|
|
3766
|
+
} = revalidatingFetchers[index];
|
|
3761
3767
|
invariant(fetcherResults !== undefined && fetcherResults[index] !== undefined, "Did not find corresponding fetcher result");
|
|
3762
3768
|
let result = fetcherResults[index]; // Process fetcher non-redirect errors
|
|
3763
3769
|
|
|
@@ -3863,8 +3869,6 @@ function getInternalRouterError(status, _temp4) {
|
|
|
3863
3869
|
errorMessage = "You made a " + method + " request to \"" + pathname + "\" but " + ("did not provide a `loader` for route \"" + routeId + "\", ") + "so there is no way to handle the request.";
|
|
3864
3870
|
} else if (type === "defer-action") {
|
|
3865
3871
|
errorMessage = "defer() is not supported in actions";
|
|
3866
|
-
} else {
|
|
3867
|
-
errorMessage = "Cannot submit binary form data using GET";
|
|
3868
3872
|
}
|
|
3869
3873
|
} else if (status === 403) {
|
|
3870
3874
|
statusText = "Forbidden";
|