Is it possible for a parent route to wait for all of its children loaders?
I have a root route that loads user authentication data, so this is loaded regardless of which route is accessed. On the initial load, I would like to load all of the data necessary in one go to show a single loading spinner and have it render the entire page without different parts flickering. Here's a screen recording of the behaviour.
What I would expect instead is for the white screen "Loading..." to not disappear until all relevant loaders have finished
Related github issue: https://github.com/TanStack/router/issues/1705
29 Replies
ambitious-aquaOP•2mo ago
StackBlitz instance: https://stackblitz.com/edit/vitejs-vite-akjyaeti?file=package.json
dakota@guardrail.ai
StackBlitz
Tanstack Router Parent + Child Loaders - StackBlitz
Next generation frontend tooling. It's fast!
sunny-green•2mo ago
you could do this
https://stackblitz.com/edit/vitejs-vite-hog6n3gh?file=src%2Froutes%2F__root.tsx,src%2Froutes%2Findex.tsx
StackBlitz
Tanstack Router Parent + Child Loaders (duplicated) - StackBlitz
Next generation frontend tooling. It's fast!
sunny-green•2mo ago
dealing with loader errors will not so be nice probably
ambitious-aquaOP•2mo ago
seems a little janky but if it works, it works
is this behaviour something that could be added to router?
sunny-green•2mo ago
maybe
ambitious-aquaOP•2mo ago
if it's something of interest I could try to work on support for it
sunny-green•2mo ago
you could first of all think of how the API could look like
ambitious-aquaOP•2mo ago
yep for sure. I try to be API-driven 🤓 I'll try to spend time on the weekend to do that.
@Manuel Schiller what do you think?
---
New route option:
loaderBehaviour
- "self"
(default)
- "waitForSubroutes"
- () => "self" | "waitForSubroutes"
self
means that the route begins to render when its own loader is complete. This should be the default to prevent a breaking change version.
waitForSubroutes
means that the route begins to render when its loader + its subroutes' loaders complete.
The third is a function that allows the user to specify what the loader behaviour should be based off of whatever attributes they deem fit. For example, for a route with parameters, they may want to wait for the subroute loaders for one parameter but not for others.
For multiple layers of subroutes, e.g.
- (root)
- /admin
- /admin/users
- /admin/users/1
We could have root
route use loaderBehaviour=waitForSubroutes
, but then /admin
uses self
, so the root route would only wait for its own loader + the /admin
route loader.
For error handling, I think it still makes sense for the error to be handled at the route that the loader failed at, regardless of the loaderBehaviour
parameter. My reasoning for this is that, in the above scenario, if the root route successfully loaded its data, but /admin
didn't, then there is enough data for the UI to render root-related content, but not admin related content.sunny-green•2mo ago
self means that the route begins to render when its own loader is complete. This should be the default to prevent a breaking change version.while this might be implicitly contained already, but a route does not render when its own loader completes. it only renders when its own loader and its parent loaders complete
ambitious-aquaOP•2mo ago
ah ok. that makes sense. so would it make sense to just stick with those 2 options (self | waitForSubroutes) and then change the description of
self
to say e.g. "The route begins to render when its own loader and its parent loaders (if any) are complete."sunny-green•2mo ago
probably
we also need to take SSR into account
or maybe not
there shouldnt be any pending components rendered in SSR so no, that's not of interest here
ambitious-aquaOP•2mo ago
I would assume (but am not sure) that anyone using SSR would try to implement "waitForSubroutes"-like behaviour – I recall doing that when I did SSR stuff at a previous job, though that was before Next and other solutions were super popular
sunny-green•2mo ago
the framing of this feature needs to be clarified some more
this is not really about the loader
it is about "keep the pending component shown until child routes are completely loaded"
another possible option could be an array of child-route ids that should be awaited
this also should probably work if the route itself does not have a loader?
ambitious-aquaOP•2mo ago
I was thinking the "array" approach but couldn't see in the loader context if one could refer to routes through an "ID"
sunny-green•2mo ago
yes you can
all routes have a unique id
ambitious-aquaOP•2mo ago
I can change the wording to be regarding the pendingComponent instead
sunny-green•2mo ago
but all of this is just syntactic sugar over
so i am a bit hesitant. it could just be a helper function that even could live in user land
ambitious-aquaOP•2mo ago
that could be fine honestly – maybe I can just add a section to the documentation to explain how to achieve this behaviour?
+ add a unit test if that's of interest?
sunny-green•2mo ago
loadPromise is not public API at the moment
if we documented that, it would be
ambitious-aquaOP•2mo ago
is making
loadPromise
public something that the team is planning on doing?sunny-green•2mo ago
right now it is just being used internally, and exposing it limits the internal reworkings we might want to do
maybe there is another level of abstraction that could hide it
ambitious-aquaOP•2mo ago
eh, we can come back to it. I don't mind using a private API for now
I've still got to do that unit test for that other issue I reported
sunny-green•2mo ago
like passing in a separate promise that is just that
ambitious-aquaOP•2mo ago
what do you mean by that? I do not understand
oh, do you mean like adding a new property to the
loader
's argument?sunny-green•2mo ago
yep
ambitious-aquaOP•2mo ago
gotcha. do you want me to make a PR for supporting that?
@Manuel Schiller I hope you don't mind the ping. I can work on this tonight, if it interests ye
sunny-green•2mo ago
sure try a small PR to provide that childLoaderPromise (or a better name if you are creative)
we should also check if this really needs loader to be prolonged
can we set wrapInSuspense:false on the child routes and then their loader would just keep the parent pending component visible?
ambitious-aquaOP•2mo ago
do you mean that should work with the existing version of tanstack-router? or would there be necessary changes to support that?
sunny-green•2mo ago
no should work right now