Replies: 8 comments 5 replies
-
I also would extend this functionality to page.tsx to archive same behavior if desired. the case of [lang] is one of the cases you don’t want page to lose the sate. |
Beta Was this translation helpful? Give feedback.
-
It would be nice to understand why the key is being set this way in the first place. There was a change recently that fixed the exact same issue on search parameter changes: 25ba8a7 @feedthejim Since you fixed that issue, can you maybe speak to the related issue of the key changing when dynamic segment parameters change? Conceptually, I'm not sure I see much of a difference between search parameters changing vs dynamic segment parameters changing. In both cases, the same React tree should remain in place. The only thing that should change is the context (accessible via Am I missing something? |
Beta Was this translation helpful? Give feedback.
-
Also possibly relevant is this PR by @timneutkens: d32ee25 He provided some good details in the description. Among other things, he mentions:
I won't pretend I have a full grasp on the various use cases and implications of that cache key. I presume that it's needed in some other parts of the app. It would be great if @timneutkens could speak to that. Even if the "dynamic parameter value" is needed in the cache key for things to work in other places, I would think it would still be reasonable to change the logic around the TemplateContext.Provider key value to avoid a complete remount of the dynamic segment. |
Beta Was this translation helpful? Give feedback.
-
This would help me a lot – we're building a pretty standard intercepting route modal/detail page setup right now, but you should be able to navigate to other instances from within the modal. This is too complicated to handle with file-based routes, but there's currently no way to opt out of nextjs routing due to it setting the key, even with catch-all routes. |
Beta Was this translation helpful? Give feedback.
-
A good compromise would be not setting the key for layouts like |
Beta Was this translation helpful? Give feedback.
-
I saw issue #48082 and I have the same issue here but with parallel routes, I also have created an issue #60037. idk if there's a solution now but your feedback looks a good solution for this. |
Beta Was this translation helpful? Give feedback.
-
I ran into this issue a couple of months ago and failed to find this discussion at that time. Let me present first my use case and problems with finding a workaround. Our app uses a /[lang]/[[...slug]] route to render pages from a CMS. Any used client component in either layout.tsx or page.tsx is fully reset during a page navigation e.g. from /en/a to /en/b. Most of the client components produce the exactly same DOM again but there are a few cases where some properties change i.e. a re-rendering would occur in normal React. Therefore strange issues occur due to the lost state: network request are done on each page navigation and screen flickers occurs because some components render their content after the network requests are done. Images and other resources might be reloaded by the browser. For instance we use an admin bar component from the CMS which gets the ID of the current page. This component internally calls fetch to check if the user is logged-in to the CMS (server-side cookie is checked). In an SPA this would only occur once in the SPA's lifetime but in this Next.js route it occurs again and again. In more complex components this will have more dramatic consequences and has performance impacts on client/server side besides screen reflow issues. For this use case it's not easy to write a workaround and in my opinion no workaround should be needed for such cases. Maintaining the React state is a fundamental feature and any side-effects should be clearly listed in the Next.js docs or even output to debug logs in dev mode. My workaround would be (again, I don't want to implement this): move the state outside the component using a global stage handler, such as Zustand. Fork the original React component and re-implement it's business logic using the global state hooks. This should work but it would be quite some overhead and each and every client component would have to be re-worked to use the global state handler. For instance search fields in a navbar are affected too by the state loss. So in my opinion Next.js should always keep the React state in (dynamic) routes. This is such an important feature of React server components. The current implementation is due to the different createRouterCacheKey(). This should be reviewed again to support client components keeping their state and making things a lot easier. A lot of people will run into this issue sooner or later. I wrote a small demo showing the issue: Links to related issues: |
Beta Was this translation helpful? Give feedback.
-
For all those who need a temporary solution. You can use This means that no state is lost when navigating between pages with dynamic segments. Also see this Codesandbox. // layout.tsx
"use client";
import { PropsWithChildren } from "react";
import { TunnelExit, TunnelProvider } from "@mittwald/react-tunnel";
export default function Layout(props: PropsWithChildren) {
const { children } = props;
return (
<>
<h1>My App</h1>
<TunnelProvider>
{children}
<TunnelExit />
</TunnelProvider>
</>
);
} // [id]/page.tsx
"use client";
import { useParams } from "next/navigation";
import { TunnelEntry } from "@mittwald/react-tunnel";
export default function Page() {
const postId = useParams().id;
return (
<TunnelEntry staticEntryId="BlogPage">
<h2>Post #{postId}</h2>
<textarea defaultValue="Change me – I will keep me state" />
</TunnelEntry>
);
} |
Beta Was this translation helpful? Give feedback.
-
Goals
The new app router resets layout and page state when navigating between pages unser a dynamic segments like
[lang]
or[[...slug]]
.Adding the option
componentKey = 'manual'
would allow the user to keep state between navigations of aLayout
orTemplate
componentUse cases
Template
component for page transitions without remounting every page on every navigation (as an alternative toLayout
that does not rerender on navigation)Non-Goals
No response
Background
The old
_app.jsx
behaviour was to keep state between navigations and to instead manually pass<Component key={path} {...pageProps} />
to force a state reset on navigation.The current layout key is applied here, this proposal would simply skip passing this key
next.js/packages/next/src/client/components/layout-router.tsx
Line 567 in 9028a16
Proposal
On layout and template files you can pass
componentKey = 'manual'
to preserve state between navigationsIf the
Layout
is not under a dynamic segment (like[lang]
or[[...slug]]
) this option will have no effect because common layouts are not rerendered.The
Template
file instead will rerender but will not changekey
, making it possible to use page transition animations without resetting state between navigationsThe possible values of
componentKey
aremanual
andauto
(the default)An alternative to this proposal would be to just remove the
key
prop and let users manually passkey={slug}
to have the current behaviour (just like it was done with_app.jsx
)Beta Was this translation helpful? Give feedback.
All reactions