vercel/next.js

Layout rerenders on same segment route change

mehrdad-shokri opened this issue · 5 comments

Link to the code that reproduces this issue

https://github.com/mehrdad-shokri/nextjs-layout-bug

To Reproduce

  1. go to http://localhost:3000/usage
  2. click "increment counter" button a couple of times
  3. click one of the links "billing", "usage", "settings"
  4. notice the counter gets reset

Current vs. Expected behavior

The layout shouldn't be remounted on same segment change as state by docs:

A layout is UI that is shared between multiple routes. On navigation, layouts preserve state, remain interactive, and do not re-render. Layouts can also be nested.

I decided to open an issue with a live example because the bug report talking about it is one years old and this hasn't been addressed.

Provide environment information

Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 23.4.0: Fri Mar 15 00:12:49 PDT 2024; root:xnu-10063.101.17~1/RELEASE_ARM64_T6020
  Available memory (MB): 32768
  Available CPU cores: 10
Binaries:
  Node: 20.12.2
  npm: 10.5.0
  Yarn: N/A
  pnpm: N/A
Relevant Packages:
  next: 14.2.3 // Latest available version is detected (14.2.3).
  eslint-config-next: 14.2.3
  react: 18.3.1
  react-dom: 18.3.1
  typescript: 5.4.5
Next.js Config:
  output: N/A

Which area(s) are affected? (Select all that apply)

Navigation

Which stage(s) are affected? (Select all that apply)

next dev (local), next start (local)

Additional context

No response

Also please note, the layout rerenders even if the layout is 'use server', confirmed it with a console.log in the layout component.

Checked with 14.3.0-canary.70 and still exists

The shared reproduction is working as intended and doesn't have a bug.

In your case, app/[dashboard]/layout.tsx should be remounted with every navigation because you're navigating between /billing, /usage, and /settings. Each of these updates the [dashboard] segment. There is no shared layout in this case. It would be a bug if your structure was /app/dashboard/layout.tsx and /app/dashboard/[param]/page.tsx, and dashboard/layout.tsx was remounted when navigating between /dashboard/1 and /dashboard/2 because /dashboard/layout.tsx is a shared layout in this case.

You are right, that was my misunderstanding of layouts and pages structure. thank you so much for clarifying.