Shallow Routing (prevent reload) #1712
Replies: 4 comments 1 reply
-
|
Whenever, your URL changes, it's considered to be a new route entry as it is in the browser. You can ofc. track this and choose to short-circuit the loader, but that'd be outside the purview of Router. |
Beta Was this translation helpful? Give feedback.
-
|
With a bit of trial and error and eventual realization this was documented, I managed to emulate this. I am using file based routing, and achieved this by having the root route defined as a named file outside of the sub-directory, e.g.: Doesn’t work: Works: Also works: Then just render the same component in both routes. This way, navigating to/from root and children seems to keep the component mounted. That said, I am not sure rendering the same component in nested routes is stable library behavior... so what seems to be a more proper way to achieve this, is to render your tabs in children routes entirely, and an |
Beta Was this translation helpful? Give feedback.
-
|
I think you could achieve this with a splat route and sessionStorage. I had a case where I needed to change the url without re-fetching data and came up with this solution. In your loader const isShallow = sessionStorage.getItem("isShallow") === "true";
sessionStorage.removeItem("isShallow");
// if it's shallow, return early
if(isShallow) {
return{
isShallow
}
}
// otherwise continue as per usualIn your component const isShallow = Route.useLoaderData({ select: (s) => s.isShallow });
// this is useful if you use tanstack query and need to pass it to the enabled param in useQueryAnd finally the actual navigation <button
onClick={(e) => {
// dont forget this!
sessionStorage.setItem("isShallow", "true");
router.navigate({
to: "/chat/$",
params: { _splat: "853c2a18-b171-4065-936d-9d99140101bc" },
});
}}
>
click me
</button> |
Beta Was this translation helpful? Give feedback.
-
|
Ran into this with a table of contents on a blog. Clicking a heading should scroll and update the URL hash - pretty standard stuff. But every click triggers 3 server calls because all my nested route loaders re-run Tried Found a workaround that actually works: set a sessionStorage flag before the history call, check it in loaders to return cached data, then clear it after a delay. // before updating hash
sessionStorage.setItem("isShallow", "true")
history.replaceState(null, "", `#${hash}`)
// in every loader
if (sessionStorage.getItem("isShallow") && cachedData) return cachedData
// clear after 1s in component
sessionStorage.removeItem("isShallow")The trick is clearing the flag after a delay (not in loaders) so all nested loaders see it. It works, but honestly it's rough. You need to add caching + the sessionStorage check to every single loader in your route tree - root, layout, page, all of them. Miss one and you're back to server calls. New dev adds a route and forgets the pattern? Broken. The 1 second delay is a magic number - too short and loaders might not have checked yet, too long and you might skip a real navigation. Each route needs its own module-level cache variable. It's a lot of fragile boilerplate for something that should just work. TanStack Router is supposed to be client-first, but intercepting native browser APIs like Would love to see something like Thanks for all the work on TanStack Router - it's genuinely great. This would make it even better! |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Is there an easy way to prevent reloading of the entire route when changing a search param? My use case is keep track of which tab menu the user is on, but updating the URL via
Route.navigatetriggers a full-page load.Beta Was this translation helpful? Give feedback.
All reactions