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
xenophobic-harlequinβ’10mo ago
you mean router.invalidate() ?
fascinating-indigoβ’10mo ago
this question needs more detail
which kind of params? path? search?
using loader()?
correct-apricotOPβ’10mo 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.fascinating-indigoβ’10mo ago
minimal example would be good
correct-apricotOPβ’9mo 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
correct-apricotOPβ’9mo ago
Navigate between the two posts. I'd like the thumb to reset between navigations, since it's local state to that page
fascinating-indigoβ’9mo ago
I see
you want what most dont want π
namely remounting
correct-apricotOPβ’9mo ago
Yes, exactly ^^
Is it doable? π¬
fascinating-indigoβ’9mo ago
everything is
correct-apricotOPβ’9mo ago
Ofc π
But is there a builtin mechanism to get this behaviour atm?
fascinating-indigoβ’9mo 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
fascinating-indigoβ’9mo ago
correct-apricotOPβ’9mo 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
fascinating-indigoβ’9mo ago
it really depends
correct-apricotOPβ’9mo 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 mostfascinating-indigoβ’9mo 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
correct-apricotOPβ’9mo ago
Huh okay interesting
I wonder what use cases they had, because I struggle to come up with them myself
fascinating-indigoβ’9mo ago
so would a
remountOnDepsChange
do the trick for you ?
(with a default on router)?correct-apricotOPβ’9mo 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, yeahfascinating-indigoβ’9mo 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
correct-apricotOPβ’9mo ago
But the only way to pass search params into loader is via loaderDeps, right?
fascinating-indigoβ’9mo ago
yes
why "but"?
correct-apricotOPβ’9mo 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
fascinating-indigoβ’9mo ago
so you would need a separate way of describing your remount dependencies then
correct-apricotOPβ’9mo 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
xenophobic-harlequinβ’9mo ago
(would it be possible to make
remountOnDepsChange
a selector function ?)correct-apricotOPβ’9mo ago
Preferrably on a global level, because I'd want that for all pages
fascinating-indigoβ’9mo ago
as I wrote above, this really depends on the individual app and interpretation
correct-apricotOPβ’9mo 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
fascinating-indigoβ’9mo ago
getting that general purpose API right is always a challenge
correct-apricotOPβ’9mo ago
Yeah for sure! One of the trickiest parts about building a router I assume π
fascinating-indigoβ’9mo 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?
correct-apricotOPβ’9mo ago
Will do!
The template picker directs me to discussions for feature requests. Still want it as an issue?
fascinating-indigoβ’9mo ago
discussions are ... crowded
i don't like the interface
correct-apricotOPβ’9mo ago
Haha ok I'll make it an issue
fascinating-indigoβ’9mo 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?
correct-apricotOPβ’9mo 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
fascinating-indigoβ’9mo 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
correct-apricotOPβ’9mo 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.
fascinating-indigoβ’9mo 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?
correct-apricotOPβ’9mo ago
No clue tbh. Haven't used React Router in a long time
fascinating-indigoβ’9mo 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...
fascinating-indigoβ’9mo 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 routercorrect-apricotOPβ’9mo 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
fascinating-indigoβ’9mo 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?
correct-apricotOPβ’9mo 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?
fascinating-indigoβ’9mo ago
I wouldnt go as far and say this is a matter of "correctness"...
correct-apricotOPβ’9mo 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.tsxfascinating-indigoβ’9mo ago
so it's 2:1 π
correct-apricotOPβ’9mo ago
Haha, touchΓ©!