vercel / next.js

The React Framework
https://nextjs.org
MIT License
121.28k stars 25.95k forks source link

router.push not working properly in intercepting modal routes. #65239

Closed stayclaxxy closed 1 week ago

stayclaxxy commented 2 weeks ago

Link to the code that reproduces this issue

https://codesandbox.io/p/devbox/parallel-routes-weird-behavior-grpnmk

To Reproduce

we can see the modal does not re-open, but the route updates.

Current vs. Expected behavior

Current:

Expected:

Provide environment information

Operating System:
  Platform: win32
  Arch: x64
  Version: Windows 10 Enterprise
  Available memory (MB): 32436
  Available CPU cores: 20
Binaries:
  Node: 20.12.2
  npm: N/A
  Yarn: N/A
  pnpm: N/A
Relevant Packages:
  next: 14.2.0-canary.47 // There is a newer canary version (14.3.0-canary.34) available, please upgrade!
  eslint-config-next: 13.5.3
  react: 18.3.1
  react-dom: 18.2.0
  typescript: 5.3.2
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 build (local), next start (local), Other (Deployed)

Additional context

I tested my issue against various canary releases, and found that https://github.com/vercel/next.js/releases/tag/v14.2.0-canary.47 is the first release I experienced this issue. It has persisted in every release since then.

ztanner commented 1 week ago

Hi @stayclaxxy! This looks to be expected behavior during soft-navigations of parallel routes. You can read a bit more about how that works in this section of the parallel routes docs. Specifically:

Soft Navigation: During client-side navigation, Next.js will perform a partial render, changing the subpage within the slot, while maintaining the other slot's active subpages, even if they don't match the current URL.

What's happening in your reproduction is that when you arrive on the /test page, the @modal slot is matched to default.tsx. Then when you trigger the interception, the @modal slot is matched to @modal/(.)broken/page.tsx. Now when you click the close button in your modal, this triggers a soft navigation back to /test. It's going to try and find a parallel route at @modal/page.tsx. A slot will never go from showing page -> default (only the reverse is possible). Since it can't find that component, it keeps what was active there before, which in this case was your modal. So your modal component is technically still mounted, but just hidden, because you called setOpen(false).

To fix this in your reproduction, you just need to create a @modal/page.tsx that returns null. Here's your CodeSandbox forked, with that change: https://codesandbox.io/p/devbox/parallel-routes-weird-behavior-forked-kdxmvj

Along with a quick demonstration:

https://github.com/vercel/next.js/assets/1939140/7c6b727b-f09f-423b-96da-88dda88eea6a