Is there a way to force throw away the previously rendered instance of the same page?
When navigating between two instances of the same page, i.e. just switching out a param, all the state of the page is maintained, which leads to bugs in our case. Is there a way to force the router to throw away the state of the old page? Like when you add a key to component
50 Replies
genetic-orangeβ’12mo ago
you mean router.invalidate() ?
foreign-sapphireβ’12mo ago
this question needs more detail
which kind of params? path? search?
using loader()?
optimistic-goldOPβ’12mo ago
Sorry, yeah path params.
So we have the route
/item/:id. On /item/1 there is a link to /item/2. In the page component there is a useState hook that holds some values. When clicking the link from to /item/2 I need the values in the useState hook to reset to their defaults. I can of course manually reset those, but that's cumbersome and error prone. I'm wondering if there's any built in mechanisms in the router that allows wiping all local state from a page component, instead of keeping it between navigations.foreign-sapphireβ’12mo ago
minimal example would be good
optimistic-goldOPβ’12mo ago
Of course! Here it is https://stackblitz.com/edit/tanstack-router-qenhmirn?file=src%2Froutes%2Fposts.%24postId.tsx
Jakob Norlin
StackBlitz
Router Basic File Based Example (forked) - StackBlitz
Run official live example code for Router Basic File Based, created by Tanstack on StackBlitz
optimistic-goldOPβ’12mo ago
Navigate between the two posts. I'd like the thumb to reset between navigations, since it's local state to that page
foreign-sapphireβ’12mo ago
I see
you want what most dont want π
namely remounting
optimistic-goldOPβ’12mo ago
Yes, exactly ^^
Is it doable? π¬
foreign-sapphireβ’12mo ago
everything is
optimistic-goldOPβ’12mo ago
Ofc π
But is there a builtin mechanism to get this behaviour atm?
foreign-sapphireβ’12mo ago
Manuel Schiller
StackBlitz
Router Basic File Based Example (forked) - StackBlitz
Run official live example code for Router Basic File Based, created by Tanstack on StackBlitz
foreign-sapphireβ’12mo ago
optimistic-goldOPβ’12mo ago
Yeah I guess that will do the trick!
But come to think of it, is keeping state really the most common use case when navigating between instances of the same page? I find it very confusing, as it's the opposite of my mental model that my useStates are local to the current instance of the page
foreign-sapphireβ’12mo ago
it really depends
optimistic-goldOPβ’12mo ago
I would expect the same result if I navigate
/posts/1 => / => /posts/2 as if I navigate /posts/1 => /posts/2, but with these defaults the behaviours are different, which probably comes as a surprise to mostforeign-sapphireβ’12mo ago
we could make it configurable in analogy to loaderDeps. when loaderDeps change, then remount the route component
you are the first to bring this up, so not sure how common this is
in fact we had the remounting behavior for a short period and we got feedback that people did not want it
optimistic-goldOPβ’12mo ago
Huh okay interesting
I wonder what use cases they had, because I struggle to come up with them myself
foreign-sapphireβ’12mo ago
so would a
remountOnDepsChange do the trick for you ?
(with a default on router)?optimistic-goldOPβ’12mo ago
But yeah if I could make a wish it would be a config on the router for a default of
defaultRemount: true/false, and then make it overridable on a route level. Or maybe even on a <Link>/navigate() level
What's included in depsChange here? I wouldn't want to remount for a search param for example
But for a route param, yeahforeign-sapphireβ’12mo ago
well then don't include them in the loaderDeps π
deps by default are only path params
and you can opt into selected search params
won't be possible on the link level
optimistic-goldOPβ’12mo ago
But the only way to pass search params into loader is via loaderDeps, right?
foreign-sapphireβ’12mo ago
yes
why "but"?
optimistic-goldOPβ’12mo ago
Because we do change loader data based on search params, and we want that to avoid remounts (I think I start to see the use cases people had with not wanting remounts). But a path param change would be considered a completely new page in our case
foreign-sapphireβ’12mo ago
so you would need a separate way of describing your remount dependencies then
optimistic-goldOPβ’12mo ago
Yeah I think so
My mental model is this: Search params modify state on the current page (which can trigger different filtering of data etc, so usually needs to be a loaderDep), and path params take you to different instances of pages, so should always force remount.
That's the behaviour I'd like to be able to configure
genetic-orangeβ’12mo ago
(would it be possible to make
remountOnDepsChange a selector function ?)optimistic-goldOPβ’12mo ago
Preferrably on a global level, because I'd want that for all pages
foreign-sapphireβ’12mo ago
as I wrote above, this really depends on the individual app and interpretation
optimistic-goldOPβ’12mo ago
Yeah ofc
I think it's a common way of treating routes, but there are for sure those who want to do it differently
foreign-sapphireβ’12mo ago
getting that general purpose API right is always a challenge
optimistic-goldOPβ’12mo ago
Yeah for sure! One of the trickiest parts about building a router I assume π
foreign-sapphireβ’12mo ago
i have some ideas, need to experiment a bit
can you please create a github issue referencing this thread and some description so we can properly track this?
optimistic-goldOPβ’12mo ago
Will do!
The template picker directs me to discussions for feature requests. Still want it as an issue?
foreign-sapphireβ’12mo ago
discussions are ... crowded
i don't like the interface
optimistic-goldOPβ’12mo ago
Haha ok I'll make it an issue
foreign-sapphireβ’12mo ago
so an issue would be preferable
how would that look like?
for individual routes I can imagine an API similar to loaderDeps
where you select the path params / search params that should trigger a remount
but on global level?
like this?
search and params being typed as the union of all values?
optimistic-goldOPβ’12mo ago
Hmm yeah that might work
I have a hard time seeing any other way that would be configured though
It makes sense to make it configurable, but also is there really that many ways to configure it?
Here's the issue btw https://github.com/TanStack/router/issues/2990
foreign-sapphireβ’12mo ago
maybe someone wants to remount only when a certain path param changes?
i don't know π
so making it configurable like this opens up all possibilities
optimistic-goldOPβ’12mo ago
Yeah I won't argue against that
Something irks me about having to add that line to every app I create to get the behaviour that I think should probably be the default. It feels like I'm adding "exotic behaviour".
But I understand my perspective is not everyones perspective, and it would also be a big and hard to track breaking change to alter the defaults.
foreign-sapphireβ’12mo ago
what should be a default needs to be discussed separately
it's also a matter of whether we consider this to be a breaking change or a bugfix
maybe the default can only change in a 2.0
btw how does react router handle this?
optimistic-goldOPβ’12mo ago
No clue tbh. Haven't used React Router in a long time
foreign-sapphireβ’12mo ago
looks like it behaves the same
https://stackoverflow.com/questions/73065621/react-router-6-never-unmount-component-when-url-parameter-changes
Stack Overflow
React router 6 never unmount component when URL parameter changes
We have a problem with the react router v6. When the URL parameters change, it is already using the mount component. Never unmount and mount the component.
Produced code example - if switching betw...
foreign-sapphireβ’12mo ago
some more questions. if you set the default as sketches above, it would apply to all routes. this would mean that upon path param change, ALL routes remount. so also all parent layouts
unless we really only pass in path params that this route defines
and should a parent path param change also remount child routes?
a different approach would be to allow setting a
RouteWrap component that router would render around the route component. then you can give it a component that sets a key based on path params
this would be much simpler to implement in routeroptimistic-goldOPβ’12mo ago
this would mean that upon path param change, ALL routes remountThis would be bad. I only expect a layout to remount if the param that changes is part of that layout's route.
should a parent path param change also remount child routesYeah I would expect it to
a different approach would be to allow setting a RouteWrap component that router would render around the route component. then you can give it a component that sets a key based on path params this would be much simpler to implement in routerYeah, but then it's really not very far from the initial solution you posted with creating a wrapper manually. Not sure adding that to the router adds much value
foreign-sapphireβ’12mo ago
I thought some more about why your remount requirement is rare
I often have routes that don't have local state
they only use search/path params
so why remount / re-render them upon param change?
so if this is ever implemented, it probably won't be the default
a layout/pathless route cannot define a path param, so this would only apply for search params then?
optimistic-goldOPβ’12mo ago
so why remount / re-render them upon param change?But as soon as you do use state, this would become a problem. So it's like a ticking time bomb bug as long as not remounting is the default. Everyone who goes from not having state to having state will be in for a surprise. With remounting as default it would be a slight deopt for those who don't have state, but without remounting as the default the outcome is buggy UIs for everyone who adds state to a page. Shouldn't correctness be considered before perf here?
foreign-sapphireβ’12mo ago
I wouldnt go as far and say this is a matter of "correctness"...
optimistic-goldOPβ’12mo ago
I guess that's on a case by case basis, but in every place in our app where we use state, it does indeed cause incorrect behaviour if it is not isolated to the current path (path as in pathname excluding search params)
Sorry I don't think I meant define a path param. Just being part of it.
Here's an example. If we have the route
/$account/_pathless-layout/$category/posts/$postId, then
* If $postId changes, only the page defined at the full route gets remounted.
* If $account changes, every single layout gets remounted
* If $category changes, the /$account and /$account/_pathless-layout layouts are not remounted, but $category and everything below it in the hierarchy is
* If a search param changes, nothing is remounted
I checked how Next.js does it, and it behaves the way I would expect here (at the page level, haven't checked all layout behaviours)
https://stackblitz.com/edit/nextjs-snnmxbxg?file=app%2F%5BpostId%5D%2Fpage.tsxforeign-sapphireβ’12mo ago
so it's 2:1 π
optimistic-goldOPβ’12mo ago
Haha, touchΓ©!