next.js: [NEXT-1208] Hot reloading in the app directory causes infinite rerenders
Verify canary release
- I verified that the issue exists in the latest Next.js canary release
Provide environment information
Operating System:
Platform: darwin
Arch: arm64
Version: Darwin Kernel Version 22.4.0: Mon Mar 6 20:59:28 PST 2023; root:xnu-8796.101.5~3/RELEASE_ARM64_T6000
Binaries:
Node: 19.9.0
npm: 9.6.3
Yarn: 1.22.19
pnpm: 8.5.1
Relevant packages:
next: 13.4.3-canary.1
eslint-config-next: N/A
react: 18.2.0
react-dom: 18.2.0
typescript: 4.9.4
Which area(s) of Next.js are affected? (leave empty if unsure)
App directory (appDir: true), Data fetching (gS(S)P, getInitialProps)
Link to the code that reproduces this issue
https://github.com/UgoRomi/hot-reload-rerender-bug
To Reproduce
- Start the project with
pnpm dev
- navigate to localhost:3000 and open the console
- edit anything (for example) the console log message in
page.tsx
orAsyncServerComponent.tsx
and save the file - Go back to the webpage and you can notice the console.log statements caused by the rerendering of the components
- As far as I can tell this only happens when there is a fetch inside a client component that has an async server component as a child. It also happens if you fetch the data using
swr
Describe the Bug
Whenever you fetch data in a Client Component that has an async Server Component as a child, hot reloading the files will cause infinite rerenders
Expected Behavior
To not have infinite rerenders
Which browser are you using? (if relevant)
No response
How are you deploying your application? (if relevant)
No response
About this issue
- Original URL
- State: open
- Created a year ago
- Reactions: 26
- Comments: 22 (3 by maintainers)
Commits related to this issue
- fix: nextjs bug https://github.com/vercel/next.js/issues/49881#issuecomment-1613911861 — committed to mohammedahmed18/Monorepo-starter-template by mohammedahmed18 10 months ago
This is still an issue in 14.0.4
We’re aware of this and exploring solutions to better handle this. In the meantime, you should use a server component for data fetching, and forward the result to a client component. This is effectively the same thing as a “data loader” like
getServerSideProps
. Learn more here.I’ve just run into this same issue and boiled it down to as small an issue as I can find
For me, all you need is an empty page inside the
/app
folder withuse client
enabledEditing anything causes an infinite loop. This happens within any file that is underneath any
use client
component, which in development mode (especially if you’re trying to view draft content) could be any file.It seems to be the combination of
use client
andasync
causing the problem. Switching to server components (obviously) does not render any console logs in the browser. Removingasync
stops the infinite loops (renders the console.log about 4 times) but also prevents data from being fetched within this component if we were to expand it.EDIT:
The workaround I’ve found is to disable any high-level
use client
components (I have a preview wrapper just under my page for showing preview datapage > preview-wrapper > template > etc
use client
should typically exist on the ‘leaves’ of your project (the outermost components) but in certain situations it can make sense to use them closer to the center - which will cause issues until this bug is resolved.This issue buries the lede.
This appears to be caused by client components being declared as async.
That is not a stable feature in React, yet, which is probably why it’s not well integrated with Next, and breaking. See Sophie’s tweet below, for more context.
Removing the async from the client component fixed it (it was never even meant to be async, and I wasn’t awaiting anything - but just returning a Promise from a client component appears to be enough to wreck havoc on Next)
https://twitter.com/sophiebits/status/1647775289790050304
How often do the infinite rerenders occur for you guys? Mine is reloading server components once pr. second 🤔
@TommySorensen - try the latest canary version - #52061 was released as part of v13.4.9-canary.2.
I do still see infinite refreshing in next dev with my dynamic routes inside of parallel routes with that version though, so I may have to create a minimal repro for it.
Update: created a minimal repro @ https://github.com/tnoor-co/next-infinite-parallel-refresh and I’ll continue to the conversation in PR linked.
@TommySorensen fixed here https://github.com/vercel/next.js/pull/52061.
@TommySorensen please ensure you are not using an
async
component that’s marked with the"use client"
directive. We just landed an ESLint rule for this as well.Me too, infinite re-render into parallel routes still exists here
@TommySorensen In my initial reproduction I didn’t have any async client components either. I had an async server component which was imported inside of a client component that fetched some data. Maybe you have something similar? If so you could try doing the data fetching in a server component, and then wrap your client component with it passing props down (Learn more here)