Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[NEXT-1208] Hot reloading in the app directory causes infinite rerenders #49881

Closed
1 task done
UgoRomi opened this issue May 16, 2023 · 29 comments
Closed
1 task done

[NEXT-1208] Hot reloading in the app directory causes infinite rerenders #49881

UgoRomi opened this issue May 16, 2023 · 29 comments
Labels
area: app App directory (appDir: true) bug Issue was opened via the bug report template. linear: next Confirmed issue that is tracked by the Next.js team. locked

Comments

@UgoRomi
Copy link

UgoRomi commented May 16, 2023

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

  1. Start the project with pnpm dev
  2. navigate to localhost:3000 and open the console
  3. edit anything (for example) the console log message in page.tsx or AsyncServerComponent.tsx and save the file
  4. Go back to the webpage and you can notice the console.log statements caused by the rerendering of the components
  5. 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

NEXT-1208

@UgoRomi UgoRomi added the bug Issue was opened via the bug report template. label May 16, 2023
@github-actions github-actions bot added area: app App directory (appDir: true) Pages Router Related to Pages Router. labels May 16, 2023
@shuding shuding added the linear: next Confirmed issue that is tracked by the Next.js team. label May 19, 2023
@shuding shuding changed the title Hot reloading in the app directory causes infinite rerenders [NEXT-1208] Hot reloading in the app directory causes infinite rerenders May 19, 2023
@danspratling
Copy link

danspratling commented May 20, 2023

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 with use client enabled

// app/test/page.tsx
"use client";

export default async function TestPage() {
  console.log("test");
  return <div className="test"> Test Page </div>;
}

Editing 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 and async causing the problem. Switching to server components (obviously) does not render any console logs in the browser. Removing async 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 data page > 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.

@bernatfortet

This comment was marked as spam.

@huyitan
Copy link

huyitan commented Jun 7, 2023

Same issue here, this bug happens even in production build.

@skworden
Copy link

skworden commented Jun 8, 2023

Im using turborepo and there was a bug in turborepo. Updating turborepo solved the issue for me.

@miguelangelrm
Copy link

miguelangelrm commented Jun 15, 2023

We're having the same issue with Next 13.4.4. We can't avoid having a high level client component since we need to inject a client side provider on the layout, perks of web3. I tried moving to 13.4.3 as @skworden mentioned it was working then, but still the same issue.

Here's my package.json in case it helps:

{
	"name": "arboretum",
	"version": "0.1.0",
	"scripts": {
		"dev": "next dev",
		"format": "prettier \"src/**/*.{css,js,json,jsx,ts,tsx}\"",
		"build": "next build",
		"format:write": "prettier --write \"src/**/*.{css,js,json,jsx,ts,tsx}\"",
		"start": "next start",
		"lint": "next lint",
		"db:push": "drizzle-kit push:mysql",
		"db:check": "drizzle-kit check:mysql"
	},
	"dependencies": {
		"@hookform/resolvers": "^3.1.0",
		"@phosphor-icons/react": "^2.0.9",
		"@planetscale/database": "^1.7.0",
		"@radix-ui/react-accordion": "^1.1.2",
		"@radix-ui/react-avatar": "^1.0.2",
		"@radix-ui/react-collapsible": "^1.0.2",
		"@radix-ui/react-dialog": "^1.0.3",
		"@radix-ui/react-dropdown-menu": "^2.0.4",
		"@radix-ui/react-label": "^2.0.1",
		"@radix-ui/react-popover": "^1.0.5",
		"@radix-ui/react-radio-group": "^1.1.3",
		"@radix-ui/react-select": "^1.2.1",
		"@radix-ui/react-separator": "^1.0.3",
		"@radix-ui/react-slot": "^1.0.1",
		"@radix-ui/react-switch": "^1.0.3",
		"@radix-ui/react-tooltip": "^1.0.6",
		"@rainbow-me/rainbowkit": "^1.0.1",
		"@t3-oss/env-nextjs": "^0.4.0",
		"@tanstack/react-query": "^4.29.12",
		"@tanstack/react-table": "8.9.1",
		"@types/node": "20.1.4",
		"@types/react": "18.2.9",
		"@types/react-dom": "18.2.4",
		"autoprefixer": "10.4.14",
		"class-variance-authority": "^0.6.0",
		"clsx": "^1.2.1",
		"cmdk": "^0.2.0",
		"connectkit": "^1.4",
		"drizzle-orm": "^0.26.5",
		"eslint": "8.40.0",
		"eslint-config-next": "13.4.2",
		"iron-session": "^6.3.1",
		"lucide-react": "^0.241.0",
		"mysql2": "^3.3.3",
		"next": "13.4.3",
		"postcss": "8.4.23",
		"react": "18.2.0",
		"react-dom": "18.2.0",
		"react-hook-form": "^7.44.2",
		"react-hot-toast": "^2.4.1",
		"react-icons": "^4.9.0",
		"siwe": "^2.1.4",
		"tailwind-merge": "^1.12.0",
		"tailwindcss": "3.3.2",
		"tailwindcss-animate": "^1.0.5",
		"tailwindcss-radix": "^2.8.0",
		"typescript": "5.1.3",
		"viem": "^0.3.39",
		"wagmi": "^1.0.9",
		"zod": "^3.21.4"
	},
	"devDependencies": {
		"drizzle-kit": "^0.18.1",
		"prettier": "^2.8.8",
		"prettier-plugin-sort-imports-desc": "^1.0.0",
		"webpack": "^5.84.1"
	}
}

Our layout structure is something like this

<html lang="en" className={inter.variable}>
	<body className="font-sans h-screen max-h-screen grid grid-rows-[min-content_1fr_min-content]"> 
		<ClientLayout>
			<SiteHeader /> // Client component
			<div className="h-full overflow-y-auto w-full">{children}</div>
			<SiteFooter /> // Client component 
			<Toaster />
		</ClientLayout>
	</body>
</html>

@arackaf
Copy link

arackaf commented Jun 25, 2023

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)

image

https://twitter.com/sophiebits/status/1647775289790050304

@leerob
Copy link
Member

leerob commented Jun 25, 2023

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.

@timtbdev
Copy link

Same issue, and it's even get worse when you add custom hooks into the component. It makes unresponsive the whole page. You can call a async function in Layout as serverClientComponent and pass it to the client component as a parameter.

@TommySorensen
Copy link

TommySorensen commented Jun 29, 2023

How often do the infinite rerenders occur for you guys? Mine is reloading server components once pr. second 🤔
image

@leerob
Copy link
Member

leerob commented Jun 29, 2023

@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.

@TommySorensen
Copy link

@leerob Thx for heads up. I'm running 13.4.8-canary.9 now with the new eslint rule. Running the linter gave 0 errors, and i also double checked all async components, and none of them have "use client". I guess i should triple check

@UgoRomi
Copy link
Author

UgoRomi commented Jun 30, 2023

@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)

@TommySorensen
Copy link

TommySorensen commented Jun 30, 2023

@leerob I found the cause of it. I'm using parallel routes where i didn't use the page.tsx since i have no use for it on that level. As soon as i added it, the reloading stopped 🎉

image
// Fixed by passing null in (shop) folder
export default function TestPage() {
  return null;
}

I guess this is a bug, since the docs does not say that the page is required at that level.

@leerob
Copy link
Member

leerob commented Jul 3, 2023

@TommySorensen fixed here #52061.

@TommySorensen
Copy link

@leerob Seems like the bug still exsist in v. 13.4.8.
I installed 13.4.8 and deleted my page.tsx that returns null. I also deleted the .next folder to check if there was some caching happening.
image

I do not have a reproduction you could test on unfortunately.

@tj-noor
Copy link

tj-noor commented Jul 5, 2023

@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.

@lei0gre
Copy link

lei0gre commented Jul 26, 2023

Me too, infinite re-render into parallel routes still exists here

mohammedahmed18 added a commit to mohammedahmed18/Monorepo-starter-template that referenced this issue Aug 25, 2023
@Ronbalt

This comment has been minimized.

@dalechyn
Copy link

Greetings.

It seems that #52362 didn't fix this and the issue is present as of now, and blocks me from using parallel routes.

A repro made by @subfallenhttps://github.com/subfallen/nested-routes-inf-refresh-repro/blob/main/README.md proves the issue still exists (#52061 (comment)):
Screenshot 2023-11-24 at 18 57 20

NextJS Version: 13.4.8-canary.15

@dalechyn
Copy link

Greetings.

It seems that #52362 didn't fix this and the issue is present as of now, and blocks me from using parallel routes.

A repro made by @subfallenhttps://github.com/subfallen/nested-routes-inf-refresh-repro/blob/main/README.md proves the issue still exists (#52061 (comment)): Screenshot 2023-11-24 at 18 57 20

NextJS Version: 13.4.8-canary.15

The merged fix #52362 might have been broken by #55026.

@dalechyn
Copy link

Greetings.

It seems that #52362 didn't fix this and the issue is present as of now, and blocks me from using parallel routes.

A repro made by @subfallenhttps://github.com/subfallen/nested-routes-inf-refresh-repro/blob/main/README.md proves the issue still exists (#52061 (comment)): Screenshot 2023-11-24 at 18 57 20

NextJS Version: 13.4.8-canary.15

Not reproducible in the latest canary.

@marcinincreo
Copy link

This is still an issue in 14.0.4

@balazsorban44 balazsorban44 removed the Pages Router Related to Pages Router. label Apr 19, 2024
@sehrish30
Copy link

I see this issue when I have both app router and pages router in my old project. The reload happens 2 3 times with full refresh of the page

@Hrishi1999
Copy link

Also had this infinite re-rendering issue with a server-side component being used within a client-side component. LazyLoading with React.Lazy() + Suspense fixed it for me :)

@blooser
Copy link

blooser commented Jun 9, 2024

When I put opengraph-image.png image into my app dir, next.js started infinity rerender loop - does any body has the same problem?

I'm using next.js 14

@devjiwonchoi
Copy link
Member

devjiwonchoi commented Aug 5, 2024

Hey everyone, this is one of the common mistake with using Client Component and Server Component together.

Let's say we have a Server Component S and Client Component C.

If you import S from C, then the S will become a Client Component as well.
This is the root cause of this issue, that a Client Component S was marked as async, which is an anti-pattern for now.

Screenshot 2024-08-06 at 12 02 01 AM

Next.js serves related error log as well.

image

Therefore we have to pass S as a children of C instead of importing it.
This is the Supported Pattern of Passing Server Components to Client Components.

Screenshot 2024-08-06 at 1 28 02 AM

I opened a PR with fix to @UgoRomi's repro, feel free to take a look at the actual migration.
For more information, please take a look at blog document, It is well documented.

@devjiwonchoi
Copy link
Member

@marcinincreo @blooser @Hrishi1999 @sehrish30

Hey everyone! Are your problem(s) related to the pattern I introduced above?
If not, could you share a reproduction to your case? I'd happy to take a look!

@devjiwonchoi
Copy link
Member

Closing as #49881 (comment) is sufficient for this issue, and is currently expected behavior in React, yet.

Copy link
Contributor

This closed issue has been automatically locked because it had no new activity for 2 weeks. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 29, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area: app App directory (appDir: true) bug Issue was opened via the bug report template. linear: next Confirmed issue that is tracked by the Next.js team. locked
Projects
None yet
Development

No branches or pull requests