Skip to content

Commit 1868148

Browse files
committed
Stabilise shouldCallHandler APIs
1 parent b6ed43d commit 1868148

File tree

5 files changed

+68
-31
lines changed

5 files changed

+68
-31
lines changed

.changeset/witty-ears-itch.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
---
2+
"react-router": minor
3+
---
4+
5+
Stabilize the `dataStrategy` `match.shouldRevalidateArgs`/`match.shouldCallHandler()` APIs.
6+
7+
- The `match.shouldLoad` API is now marked deprecated in favor of these more powerful alternatives
8+
- If you're using this API in a custom `dataStrategy` today, you can swap to the new API at your convenience:
9+
10+
```tsx
11+
// Before
12+
const matchesToLoad = matches.filter((m) => m.shouldLoad);
13+
14+
// After
15+
const matchesToLoad = matches.filter((m) => m.shouldCallHandler());
16+
```
17+
18+
- `match.shouldRevalidateArgs` is the argument that will be passed to the route `shouldRevaliate` function
19+
- Combined with the parameter accepted by `match.shouldCallHandler`, you can define a custom revalidation behavior for your `dataStrategy`:
20+
21+
```tsx
22+
const matchesToLoad = matches.filter((m) => {
23+
const defaultShouldRevalidate = customRevalidationBehavior(
24+
match.shouldRevalidateArgs,
25+
);
26+
return m.shouldCallHandler(defaultShouldRevalidate);
27+
// The argument here will override the internal `defaultShouldRevalidate` value
28+
});
29+
```

packages/react-router/__tests__/router/should-revalidate-test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1200,11 +1200,11 @@ describe("shouldRevalidate", () => {
12001200
async dataStrategy({ request, matches }) {
12011201
let keyedResults = {};
12021202
let matchesToLoad = matches.filter((match) =>
1203-
match.unstable_shouldCallHandler(
1203+
match.shouldCallHandler(
12041204
request.method === "POST"
12051205
? undefined
1206-
: !match.unstable_shouldRevalidateArgs?.actionStatus ||
1207-
match.unstable_shouldRevalidateArgs.actionStatus < 400,
1206+
: !match.shouldRevalidateArgs?.actionStatus ||
1207+
match.shouldRevalidateArgs.actionStatus < 400,
12081208
),
12091209
);
12101210
await Promise.all(

packages/react-router/lib/dom/ssr/single-fetch.tsx

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ export function getSingleFetchDataStrategyImpl(
219219

220220
let foundRevalidatingServerLoader = matches.some((m) => {
221221
let { hasLoader, hasClientLoader } = getRouteInfo(m);
222-
return m.unstable_shouldCallHandler() && hasLoader && !hasClientLoader;
222+
return m.shouldCallHandler() && hasLoader && !hasClientLoader;
223223
});
224224
if (!ssr && !foundRevalidatingServerLoader) {
225225
// If this is SPA mode, there won't be any loaders below root and we'll
@@ -282,7 +282,7 @@ async function singleFetchActionStrategy(
282282
fetchAndDecode: FetchAndDecodeFunction,
283283
basename: string | undefined,
284284
) {
285-
let actionMatch = args.matches.find((m) => m.unstable_shouldCallHandler());
285+
let actionMatch = args.matches.find((m) => m.shouldCallHandler());
286286
invariant(actionMatch, "No action match found");
287287
let actionStatus: number | undefined = undefined;
288288
let result = await actionMatch.resolve(async (handler) => {
@@ -321,9 +321,7 @@ async function nonSsrStrategy(
321321
fetchAndDecode: FetchAndDecodeFunction,
322322
basename: string | undefined,
323323
) {
324-
let matchesToLoad = args.matches.filter((m) =>
325-
m.unstable_shouldCallHandler(),
326-
);
324+
let matchesToLoad = args.matches.filter((m) => m.shouldCallHandler());
327325
let results: Record<string, DataStrategyResult> = {};
328326
await Promise.all(
329327
matchesToLoad.map((m) =>
@@ -385,15 +383,15 @@ async function singleFetchLoaderNavigationStrategy(
385383
getRouteInfo(m);
386384

387385
let defaultShouldRevalidate =
388-
!m.unstable_shouldRevalidateArgs ||
389-
m.unstable_shouldRevalidateArgs.actionStatus == null ||
390-
m.unstable_shouldRevalidateArgs.actionStatus < 400;
391-
let shouldCall = m.unstable_shouldCallHandler(defaultShouldRevalidate);
386+
!m.shouldRevalidateArgs ||
387+
m.shouldRevalidateArgs.actionStatus == null ||
388+
m.shouldRevalidateArgs.actionStatus < 400;
389+
let shouldCall = m.shouldCallHandler(defaultShouldRevalidate);
392390

393391
if (!shouldCall) {
394392
// If this route opted out, don't include in the .data request
395393
foundOptOutRoute ||=
396-
m.unstable_shouldRevalidateArgs != null && // This is a revalidation,
394+
m.shouldRevalidateArgs != null && // This is a revalidation,
397395
hasLoader && // for a route with a server loader,
398396
hasShouldRevalidate === true; // and a shouldRevalidate function
399397
return;
@@ -538,7 +536,7 @@ async function singleFetchLoaderFetcherStrategy(
538536
fetchAndDecode: FetchAndDecodeFunction,
539537
basename: string | undefined,
540538
) {
541-
let fetcherMatch = args.matches.find((m) => m.unstable_shouldCallHandler());
539+
let fetcherMatch = args.matches.find((m) => m.shouldCallHandler());
542540
invariant(fetcherMatch, "No fetcher match found");
543541
let routeId = fetcherMatch.route.id;
544542
let result = await fetcherMatch.resolve(async (handler) =>

packages/react-router/lib/router/router.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5695,7 +5695,7 @@ function runClientMiddlewarePipeline(
56955695
),
56965696
// or the shallowest route that needs to load data
56975697
Math.max(
5698-
matches.findIndex((m) => m.unstable_shouldCallHandler()),
5698+
matches.findIndex((m) => m.shouldCallHandler()),
56995699
0,
57005700
),
57015701
);
@@ -5874,10 +5874,10 @@ function getDataStrategyMatch(
58745874
lazyRoutePropertiesToSkip: string[],
58755875
scopedContext: unknown,
58765876
shouldLoad: boolean,
5877-
unstable_shouldRevalidateArgs: DataStrategyMatch["unstable_shouldRevalidateArgs"] = null,
5877+
shouldRevalidateArgs: DataStrategyMatch["shouldRevalidateArgs"] = null,
58785878
): DataStrategyMatch {
58795879
// The hope here is to avoid a breaking change to the resolve behavior.
5880-
// Opt-ing into the `unstable_shouldCallHandler` API changes some nuanced behavior
5880+
// Opt-ing into the `shouldCallHandler` API changes some nuanced behavior
58815881
// around when resolve calls through to the handler
58825882
let isUsingNewApi = false;
58835883

@@ -5893,20 +5893,20 @@ function getDataStrategyMatch(
58935893
...match,
58945894
_lazyPromises,
58955895
shouldLoad,
5896-
unstable_shouldRevalidateArgs,
5897-
unstable_shouldCallHandler(defaultShouldRevalidate) {
5896+
shouldRevalidateArgs,
5897+
shouldCallHandler(defaultShouldRevalidate) {
58985898
isUsingNewApi = true;
5899-
if (!unstable_shouldRevalidateArgs) {
5899+
if (!shouldRevalidateArgs) {
59005900
return shouldLoad;
59015901
}
59025902

59035903
if (typeof defaultShouldRevalidate === "boolean") {
59045904
return shouldRevalidateLoader(match, {
5905-
...unstable_shouldRevalidateArgs,
5905+
...shouldRevalidateArgs,
59065906
defaultShouldRevalidate,
59075907
});
59085908
}
5909-
return shouldRevalidateLoader(match, unstable_shouldRevalidateArgs);
5909+
return shouldRevalidateLoader(match, shouldRevalidateArgs);
59105910
},
59115911
resolve(handlerOverride) {
59125912
let { lazy, loader, middleware } = match.route;
@@ -5951,7 +5951,7 @@ function getTargetedDataStrategyMatches(
59515951
targetMatch: AgnosticDataRouteMatch,
59525952
lazyRoutePropertiesToSkip: string[],
59535953
scopedContext: unknown,
5954-
shouldRevalidateArgs: DataStrategyMatch["unstable_shouldRevalidateArgs"] = null,
5954+
shouldRevalidateArgs: DataStrategyMatch["shouldRevalidateArgs"] = null,
59555955
): DataStrategyMatch[] {
59565956
return matches.map((match) => {
59575957
if (match.route.id !== targetMatch.route.id) {
@@ -5960,8 +5960,8 @@ function getTargetedDataStrategyMatches(
59605960
return {
59615961
...match,
59625962
shouldLoad: false,
5963-
unstable_shouldRevalidateArgs: shouldRevalidateArgs,
5964-
unstable_shouldCallHandler: () => false,
5963+
shouldRevalidateArgs: shouldRevalidateArgs,
5964+
shouldCallHandler: () => false,
59655965
_lazyPromises: getDataStrategyMatchLazyPromises(
59665966
mapRouteProperties,
59675967
manifest,

packages/react-router/lib/router/utils.ts

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,8 @@ export interface DataStrategyMatch
434434
route: Promise<void> | undefined;
435435
};
436436
/**
437+
* @deprecated Deprecated in favor of `shouldCallHandler`
438+
*
437439
* A boolean value indicating whether this route handler should be called in
438440
* this pass.
439441
*
@@ -459,12 +461,20 @@ export interface DataStrategyMatch
459461
* custom `shouldRevalidate` implementations)
460462
*/
461463
shouldLoad: boolean;
462-
// This can be null for actions calls and for initial hydration calls
463-
unstable_shouldRevalidateArgs: ShouldRevalidateFunctionArgs | null;
464-
// This function will use a scoped version of `shouldRevalidateArgs` because
465-
// they are read-only but let the user provide an optional override value for
466-
// `defaultShouldRevalidate` if they choose
467-
unstable_shouldCallHandler(defaultShouldRevalidate?: boolean): boolean;
464+
/**
465+
* Arguments passed to the `shouldRevalidate` function for this `loader` execution.
466+
* Will be `null` if this is not a revalidating loader {@link DataStrategyMatch}.
467+
*/
468+
shouldRevalidateArgs: ShouldRevalidateFunctionArgs | null;
469+
/**
470+
* Determine if this route's handler should be called during this `dataStrategy`
471+
* execution. Calling it with no arguments will leverage the default revalidation
472+
* behavior. You can pass your own `defaultShouldRevalidate` value if you wish
473+
* to change the default revalidation behavior with your `dataStrategy`.
474+
*
475+
* @param defaultShouldRevalidate `defaultShouldRevalidate` override value (optional)
476+
*/
477+
shouldCallHandler(defaultShouldRevalidate?: boolean): boolean;
468478
/**
469479
* An async function that will resolve any `route.lazy` implementations and
470480
* execute the route's handler (if necessary), returning a {@link DataStrategyResult}

0 commit comments

Comments
 (0)