-
- Notifications
You must be signed in to change notification settings - Fork 10.7k
unstable_dataStrategy refactor for better single fetch support #11943
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
unstable_dataStrategy refactor for better single fetch support #11943
Conversation
🦋 Changeset detectedLatest commit: 47d9a97 The changes in this PR will be included in the next version bump. This PR includes changesets to release 5 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
function keyedResults( | ||
matches: DataStrategyMatch[], | ||
results: HandlerResult[] | ||
) { | ||
return results.reduce( | ||
(acc, r, i) => | ||
Object.assign( | ||
acc, | ||
matches[i].shouldLoad ? { [matches[i].route.id]: r } : {} | ||
), | ||
{} | ||
); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the primary user-facing (breaking) change to unstable_dataStrategy
in that instead of returning a HandlerResult[]
(as a parallel array to matchesToLoad
), you now return a Record<string, HandlerResult>
which allows you to deviate from the internal matchesToLoad
and provide (or not provide) fresh data for any active routes. This is how Remix will choose to revalidate existing ancestor routes by default.
null | ||
); | ||
result = results[0]; | ||
result = results[actionMatch.route.id]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Results are keyed by routeId now, not indexed
return await Promise.all( | ||
results.map((result, i) => { | ||
if (isRedirectHandlerResult(result)) { | ||
let response = result.result as Response; | ||
return { | ||
type: ResultType.redirect, | ||
response: normalizeRelativeRoutingRedirectResponse( | ||
response, | ||
request, | ||
matchesToLoad[i].route.id, | ||
matches, | ||
basename, | ||
future.v7_relativeSplatPath | ||
), | ||
}; | ||
} | ||
| ||
return convertHandlerResultToDataResult(result); | ||
}) | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is just moved down below to scope the try/catch to callDataStrategyImpl
// Kick off loaders and fetchers in parallel | ||
let loaderResultsPromise = matchesToLoad.length | ||
? callDataStrategy("loader", state, request, matchesToLoad, matches, null) | ||
: Promise.resolve({} as Record<string, DataResult>); | ||
| ||
let fetcherResultsPromise = Promise.all( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These still run in parallel but separating them from the singular Promise.all
made it a bit easier to work with the new keyed object return value
return Promise.resolve({ | ||
[f.key]: { | ||
type: ResultType.error, | ||
error: getInternalRouterError(404, { | ||
pathname: f.path, | ||
}), | ||
} as ErrorResult, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fetchers are keyed by the fetcherKey
from here outward, not the routeId
, since you could have multiple fetchers hitting the same route
); | ||
| ||
await Promise.all([ | ||
resolveDeferredResults( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was also split to 2 separate implementations since they did't share the majorty of the code anymore
): Promise<Record<string, HandlerResult>> { | ||
let loadRouteDefinitionsPromises = matches.map((m) => | ||
m.route.lazy | ||
? loadLazyRouteModule(m.route, mapRouteProperties, manifest) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We kick these off up front now, to remove the need for folks to call resolve()
for all matches
type, | ||
request, | ||
match, | ||
loadRoutePromise, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then we pass the route.lazy
promise into callLoaderOrAction
so it can be awaited internally
export interface DataStrategyFunctionArgs<Context = any> | ||
extends DataFunctionArgs<Context> { | ||
matches: DataStrategyMatch[]; | ||
fetcherKey: string | null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are passing the fetcherKey
into dataStrategy
now for fetcher cals which allows Remix to make one-off calls and not run any parent handlers in the single fetch request
8e3cb89
to b74306e
Compare 🤖 Hello there, We just published version Thanks! |
🤖 Hello there, We just published version Thanks! |
🤖 Hello there, We just published version Thanks! |
No description provided.