beforeLoad and pendingComponent behaviour
could someone help me understand how exactly does this work, in the docs I saw the below explaination for beforeLoad
If this function returns a promise, the route will be put into a pending state and cause rendering to suspend until the promise resolves. If this route's pendingMs threshold is reached, the pendingComponent will be shown until it resolves. If the promise rejects, the route will be put into an error state and the error will be thrown during render.
(https://tanstack.com/router/latest/docs/framework/react/api/router/RouteOptionsType#beforeload-method)
I tried to debug and understand using console logs, it so happens, the execution happens in this order
1. before starts executing
2. pending component
3. component
4. pending component
I was not expecting component to be rendered before pending state has finished. since that is causing subtle issues, also not matching with docs currently.
12 Replies
automatic-azure•2w ago
Still learning myself, so not going to attempt to answer in my own words, but I found this article helpful
apparent-cyanOP•2w ago
the article also says beforeLoad blocks all the loaders, it doesn't mention anything about the component being rendered during the time beforeLoad is executing
I am not sure if this is a bug or expected behavior, can someone confirm?
flat-fuchsia•2w ago
BeforeLoad will run in order of matches. So if you have three routes, before load for the first will run, then second, then third. Once all beforeLoad functions have run, then all loaders start at the same time.
If you have any loader that is running asynchronously, then the router will wait for that loader to finish before mounting your component.
If a child loader finishes before a parent, it will not render the component, because the parent has not yet mounted the component that contains the outlet for which the child route is rendered inside of.
If you are seeing
1. before starts executing
2. pending component
3. component
4. pending component
Then the most common reason for this is that you have something in your component which is triggering a suspense boundary - as the
pending component acts as a suspense boundary for your route.
For example, imagine you have this
Then you will see the pending component while loader runs, then it will mount your route component, then it will suspend and you will see the pending component again.apparent-cyanOP•2w ago
Thanks for explaining in such detail, great explaination. so you are saying if we have something which can trigger a suspense then only this kind of scenario might happen. which makes sense.
I do have authClient.useSession under SignedOut and SignedIn components, which might be triggering suspense boundary. I am not completely sure.
my question is, in all cases the beforeLoad function should complete before it starts mounting the component?
I will also try to share the relevant code if that helps
apparent-cyanOP•2w ago
this is the github repo link for my root route setup
https://github.com/amanmavai/mn_projects/blob/main/apps/tanstack_router_space/src/routes/root.tsx
since I am continuously working on this repo, this particular issue can be reproduced at git tag, v4, if someone needs to check it
GitHub
mn_projects/apps/tanstack_router_space/src/routes/__root.tsx at mai...
Contribute to amanmavai/mn_projects development by creating an account on GitHub.
apparent-cyanOP•2w ago
you can find other files in there as well, esp https://github.com/amanmavai/mn_projects/blob/main/apps/tanstack_router_space/src/components/auth-components.tsx
GitHub
mn_projects/apps/tanstack_router_space/src/components/auth-componen...
Contribute to amanmavai/mn_projects development by creating an account on GitHub.
apparent-cyanOP•2w ago
mostly I am seeing this behaviour while loggin out and logging in, if you wanna run the app, its basically a bun monorepo. so the command to run backend is
bun --filter bun_api_space dev and command to run frontend is bun --filter tanstack_router_space dev after that you can go to login page there is register section from where you can signup and test this functionalityflat-fuchsia•2w ago
Yep. The simplest way to think of beforeLoad is as middleware. Nothing else about your route should run until all before load is completed.
If I get a chance, I’ll check out your repo later today (just woke up haha)
apparent-cyanOP•2w ago
actually the issue is, I am creating authClient in beforeLoad using tanstack query, but when I do signout, beforeLoad starts executing and before it completes execution, SignedOut component which is rendered in header executes again and it doesn't have authClient (this indicates that beforeLoad didn't finish in its entirety).
flat-fuchsia•2w ago
If you are clearing the queryCache, in a component that isn't being unmounted during the navigation (your header exists in application globally so this would be the case as you mentioned), then that component is free to re-render while beforeLoad is running, since it will not be unmounted during the navigation. Therefore, tanstack query will re-render your header immediately upon auth change, even while before load is running.
When we logout in my works application, we have a loader that sits in the root route and can be set to loading from a global store with
setAppLoading which puts a loader over the entire application, so we don't really encounter this issue even if it would be coming up. 🤷♂️apparent-cyanOP•2w ago
so does this only happen during navigations and not on initial load? since initial load we do not have existing components when beforeLoad first starts executing
flat-fuchsia•2w ago
That is my understanding from experience (have not read the source code for this).
And it makes sense, on initial load, the router hasn't decided what to mount yet, so it's just going to render the wrapper around the router until the router has decided what routes to show (since before load can also trigger redirects/etc). But when the route you are on has already mounted, it's not going to unmount the components before every navigation, otherwise you would lose all your state for the existing components that are mounted