next.js
next.js copied to clipboard
App Dir is caching renders even with "dynamic" set to "force-dynamic"
Verify canary release
- [X] I verified that the issue exists in the latest Next.js canary release
Provide environment information
Operating System: Platform: linux Arch: x64 Version: #14 SMP Sat Jun 4 00:16:10 CEST 2022 Binaries: Node: 16.17.0 npm: 8.15.0 Yarn: 1.22.19 pnpm: 7.1.0 Relevant packages: next: 13.0.2 eslint-config-next: N/A react: 18.2.0 react-dom: 18.2.0
What browser are you using? (if relevant)
Chrome
How are you deploying your application? (if relevant)
next start
Describe the Bug
When clicking on <Link /> to go to a page that has "dynamic" segment config set to "force-dynamic" the page still uses a cached render from a previous visit.
Expected Behavior
The "force-dynamic" config should make the page render again each time you visit the page through <Link /> or any other client side transition.
Link to reproduction
https://stackblitz.com/edit/nextjs-sxijav?file=package.json,app%2Fnested%2Fpage.tsx
To Reproduce
- Click link to go to the nested page
- A random number will show
- Click link to go to home page
- Click link to go to nested page
- Bug: Same number shows (Expected: Different number)
Manually setting cache: "no-store"
on all the fetch calls doesn't work [to make the page dynamic] either.
It is because of soft navigation, with the new layouts nextjs does soft navigation by default, when your page has not been rendered already and the user navigates to it with a link component, it does not rerender the page each time.
What the nextjs team said is that your page should rerender if you do a mutation with their upcoming mutation, or if you call router.refresh
.
It is a PIA i think because the mental model of dynamic pages is that it should rerender each time you go to them.
Update : I tried to disable prefetching of links to force rerendering but it disables client side page navigation, im gonna open an issue for this
From the docs link above:
On navigation, Next.js will prioritize using soft navigation if the route you are navigating to has been prefetched, and either doesn't include dynamic segments or has the same dynamic parameters as the current route.
So not only a PITA, it doesn't work when data is dynamic but not dynamic based on route params (i.e. data that changes frequently, or data that changes based on current user / http headers). How are we supposed to force hard navigation in these cases?
Rather than adding more exceptions to the rules of when Next.js will use soft vs hard navigation, I would rather see it simplified.
It does feel misleading that a "force-dynamic" page will still use a soft render. There should be some place in the docs suggesting something like...
useState(() => router.refresh())
Or some other way to have this run on the first render only. I don't think this is very elegant.
@gfortaine
It looks like that you are doing Client-Side Navigation with a Server Component. Simply add the https://github.com/reactjs/rfcs/pull/227 at the top of the NestedPage component. Then, you will notice that it will trigger a re-render on client-side transition using next/link
There is a problem though : it causes hydration mismatches, as you can see in the screenshot below :
And what about data fetching ? I've tweaked the example and make it fetch a random number instead on the server : https://stackblitz.com/edit/nextjs-zskblw?file=next.config.js,app%2Fnested%2Fpage.tsx
And wether i add a cache: no-store
or next: { revalidate: 0 }
it still does a soft navigation and the user needs to reload the page fully to see a different number.
@gfortaine , the solution you’re suggesting is to use the use
hook, but this hook lead to infinite fetches, so no it’s not a viable solution, at least for now. Since use
is not a stable API right now, and is supposed to come with the cache
api in react.
https://github.com/vercel/next.js/issues/42180
Yes use
is an experimental, but the RFC hasn’t landed yet and the infinite fetches seems to be more of react issue than NextJs.
I wouldn’t recommend this since it is still heavily in development and the default behaviour now is not optimal.
indeed there is a clear case where it leads to infinite fetches : when we start directly on the /nested path. But clicking on /nested in / is OK. Thus, it looks like that Next.js doesn't handle use very well right now.
Still one odd thing I noticed is that it still does at least 3 or 4 fetches (which is isn’t supposed to be the case, right ?)
At least with the "use client"
it should only fetch twice : once in the server and the second time in client during hydration.
But it fetches once in the server and 3 or 4 more in the client.
According to the following comment, it seems that one should create a new root layout (/nested
) to trigger a hard navigation :
https://github.com/vercel/next.js/discussions/41745#discussioncomment-3985483
@gfortaine I've put up an example with that in mind : https://stackblitz.com/edit/nextjs-wxc4fy But In my opinion, that is some pretty hacky way to solve this. And i don't think this would be a viable solution...
I still think this is not good enough, and they should this fix... or at least indicate in the doc a way around this.
What is weird, is that when using a dynamic route segment, a hard navigation always occurs : https://stackblitz.com/edit/nextjs-51tdbm?file=app%2F[any]%2Fpage.tsx
I think this is indeed a bug
What is weird, is that when using a dynamic route segment, a hard navigation always occurs : https://stackblitz.com/edit/nextjs-51tdbm?file=app%2F[any]%2Fpage.tsx
@Fredkiss3 Just pointing out that this is the documented behavior. See https://beta.nextjs.org/docs/routing/linking-and-navigating#soft-navigation :
On navigation, Next.js will prioritize using soft navigation if the route you are navigating to has been prefetched, and either doesn't include dynamic segments or has the same dynamic parameters as the current route.
Of course there's still an issue with this documented behavior..
What are we supposed to do when we have dynamic data that changes frequently? Or data that depends on authentication state? Currently stale data will be shown until user does a manual refresh, or we need some hack to force a "hard refresh" (useState(() => router.refresh())
, which, how do we do that and avoid fetching data twice in the cases where data wasn't fetched before?).
Closing in favor of #42991
This closed issue has been automatically locked because it had no new activity for a month. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.