You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Last month at Reactathon, Ryan Florence made the case for nested routes vs. "nested routers" in child components for efficient data loading, in his When To Fetch talk: https://www.youtube.com/watch?v=95B8mnhzoCM
This is reminiscent of the transitionWhile() of the new Navigation API that came to Chrome 102 at the end of last month.
IMO this should be built into any modern router library:
include a loader callback or similar that returns some data, ideally the callback would receive a Signal in case the navigation is cancelled
declare nested routes (could possibly be a Routes object as a routes or nested property of each route, such that the Routes.outlet() can be used in the components), the goal being that the loader for nested routes are declared as soon and up as possible, rather than within other components, so data for nested routes can load in parallel rather than in cascade
ideally render would be called once all data has finished loaded, with the route's data as argument in addition to the route params; this would mimic a full-page navigation, and if someone wants to use a spinner or other skeleton component while loading they could have the loader return immediately with an object wrapping a Promise (then render can use the until() directive to handle what to display while data is actually loading).
Ideally, the URL when using goto() (possibly by a caught click event) would only change once all the loader callbacks (of nested routes) have resolved. Once the Navigation API ships (even) more widely (or there's a stable polyfill), the loader would be used as NavigateEvent#transitionWhile() and the signal would come from the NavigateEvent#signal, the browser would then be responsible for updating the URL at the appropriate time (and that would then also work when traversing the history!)
In case of error in any loader (there can be many with nested routes), navigation should be globally cancelled (so the URL doesn't change), and because render wouldn't have been called either, the user could re-try the navigation. There needs to be a callback or event though so an error message can be displayed to the user (e.g. in a toast).
Alternatively, render could possibly be called early with the loading data's Promise (but only once the parent route has settled), and the method could possibly return noChange or some other sentinel value, or a Promise, to keep showing the same screen, only updating when a real renderable is returned. So return html`${until(loaderData.then(d => html`<x-page .data=${d}></x-page>`, () => html`error`), noChange)}`; or return loaderData.then(d => html`<x-page .d=${d}></x-page>`, () => html`error`); could be used to only update the screen once the data has finished loading. If you want a spinner/skeleton, then use until(): return html`${until(loaderData.then(d => html`<x-page .data=${d}></x-page>`, () => html`error`), html`<x-spinner></x-spinner>`)}`;
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
-
Last month at Reactathon, Ryan Florence made the case for nested routes vs. "nested routers" in child components for efficient data loading, in his When To Fetch talk: https://www.youtube.com/watch?v=95B8mnhzoCM
This is reminiscent of the
transitionWhile()
of the new Navigation API that came to Chrome 102 at the end of last month.IMO this should be built into any modern router library:
loader
callback or similar that returns some data, ideally the callback would receive aSignal
in case the navigation is cancelledRoutes
object as aroutes
ornested
property of each route, such that theRoutes.outlet()
can be used in the components), the goal being that theloader
for nested routes are declared as soon and up as possible, rather than within other components, so data for nested routes can load in parallel rather than in cascaderender
would be called once all data has finished loaded, with the route's data as argument in addition to the route params; this would mimic a full-page navigation, and if someone wants to use a spinner or other skeleton component while loading they could have theloader
return immediately with an object wrapping aPromise
(thenrender
can use theuntil()
directive to handle what to display while data is actually loading).Ideally, the URL when using
goto()
(possibly by a caught click event) would only change once all theloader
callbacks (of nested routes) have resolved. Once the Navigation API ships (even) more widely (or there's a stable polyfill), theloader
would be used asNavigateEvent#transitionWhile()
and the signal would come from theNavigateEvent#signal
, the browser would then be responsible for updating the URL at the appropriate time (and that would then also work when traversing the history!)In case of error in any
loader
(there can be many with nested routes), navigation should be globally cancelled (so the URL doesn't change), and becauserender
wouldn't have been called either, the user could re-try the navigation. There needs to be a callback or event though so an error message can be displayed to the user (e.g. in a toast).Alternatively,
render
could possibly be called early with the loading data'sPromise
(but only once the parent route has settled), and the method could possibly returnnoChange
or some other sentinel value, or aPromise
, to keep showing the same screen, only updating when a real renderable is returned. Soreturn html`${until(loaderData.then(d => html`<x-page .data=${d}></x-page>`, () => html`error`), noChange)}`;
orreturn loaderData.then(d => html`<x-page .d=${d}></x-page>`, () => html`error`);
could be used to only update the screen once the data has finished loading. If you want a spinner/skeleton, then useuntil()
:return html`${until(loaderData.then(d => html`<x-page .data=${d}></x-page>`, () => html`error`), html`<x-spinner></x-spinner>`)}`;
Beta Was this translation helpful? Give feedback.
All reactions