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

Catch-all parallel routes don't receive params if a normal route matches the path #62539

Closed
nicolo-tito opened this issue Feb 26, 2024 · 11 comments · Fixed by #65063
Closed

Catch-all parallel routes don't receive params if a normal route matches the path #62539

nicolo-tito opened this issue Feb 26, 2024 · 11 comments · Fixed by #65063
Labels
bug Issue was opened via the bug report template. locked Parallel & Intercepting Routes Related to Parallel and/or Intercepting routes.

Comments

@nicolo-tito
Copy link

nicolo-tito commented Feb 26, 2024

Link to the code that reproduces this issue

https://codesandbox.io/p/devbox/parallel-routes-params-tfz5pp

To Reproduce

  1. Start application
  2. Click on the link

Current vs. Expected behavior

Current behavior: the catch-all parallel route don't receive any param, while the normal route receives params as expected.
Expected behavior: catch-all parallel route receives params, as it currently happens when no normal route matches the path.

Provide environment information

Operating System:
  Platform: linux
  Arch: x64
  Version: #1 SMP PREEMPT_DYNAMIC Sun Aug  6 20:05:33 UTC 2023
  Available memory (MB): 4102
  Available CPU cores: 2
Binaries:
  Node: 20.9.0
  npm: 9.8.1
  Yarn: 1.22.19
  pnpm: 8.10.2
Relevant Packages:
  next: 14.1.1-canary.73 // Latest available version is detected (14.1.1-canary.73).
  eslint-config-next: N/A
  react: 18.2.0
  react-dom: 18.2.0
  typescript: 5.1.3
Next.js Config:
  output: N/A

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

App Router, Routing (next/router, next/navigation, next/link)

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

next dev (local), next build (local), next start (local), Vercel (Deployed), Other (Deployed)

Additional context

No response

@nicolo-tito nicolo-tito added the bug Issue was opened via the bug report template. label Feb 26, 2024
@nicolo-tito nicolo-tito changed the title Catch-all parallel routes don't receive params if a normal routes exists for same path Catch-all parallel routes don't receive params if a normal routes exists for the same path Feb 26, 2024
@github-actions github-actions bot added the Navigation Related to Next.js linking (e.g., <Link>) and navigation. label Feb 26, 2024
@nicolo-tito nicolo-tito changed the title Catch-all parallel routes don't receive params if a normal routes exists for the same path Catch-all parallel routes don't receive params if a normal routes match the path Feb 26, 2024
@nicolo-tito nicolo-tito changed the title Catch-all parallel routes don't receive params if a normal routes match the path Catch-all parallel routes don't receive params if a normal route match the path Feb 26, 2024
@nicolo-tito
Copy link
Author

nicolo-tito commented Feb 26, 2024

As a side note: if the catch-all parallel route were to receive the params organized in the same way as the matching normal route

e.g.
path: company/companyId/user/userId
url: company/23/user/34
params: {
    companyId: 23,
    userId: 34
}

that would be awesome for a number of use cases where url data is needed server-side (quite long discussion here), like achieving a server rendered breadcrumb component (breadcrumbs often need access to server resources, as displayed breadcrumbs don't necessarily match the path name. E.g. user id in the path, user name displayed in the breadcrumb).
I recognize this could possibly feel a bit too opinionated, with regard to Next.js dynamic params folder structure. Maybe it could be a separated prop exclusively available in parallel routes:

Parallel route props:
{
  // Classic params, so for a catch-all it's just one param with a string array
  params: { slug: string | string[] }
  // Params as they are parsed for the current matching non-parallel route
  mainRouteParams: { slug: string }
  searchParams: { [key: string]: string | string[] | undefined }
}

But anyway, this could be also achievable just by having the params as a string array, like it already happens in catch all routes, so that would be a great start.

@nicolo-tito nicolo-tito changed the title Catch-all parallel routes don't receive params if a normal route match the path Catch-all parallel routes don't receive params if a normal route matches the path Feb 26, 2024
@michaelschufi
Copy link

We are experiencing the same thing. Have you found some kind of workaround?

@nicolo-tito
Copy link
Author

No, it doesn't look there's a workaround here. If a maintainer confirms that this is a bug, I could possibly look into submitting a PR, but I first want to be sure it's not intended behavior (and that a fix is welcome).

@balazsorban44 balazsorban44 added Parallel & Intercepting Routes Related to Parallel and/or Intercepting routes. and removed Navigation Related to Next.js linking (e.g., <Link>) and navigation. labels Apr 19, 2024
@philwolstenholme
Copy link
Contributor

I'm experiencing this too, when I was trying to implement breadcrumbs via parallel routes using this file structure

This is the page.tsx that's missing params:

├── @above
│   ├── [...path]
│   │   └── page.tsx 👈👈👈👈👈👈 this is the page with the empty params

@philwolstenholme
Copy link
Contributor

@ztanner would you mind adding this to your list of parallel routes issues, and let us know if it's expected behaviour or a bug?

@ztanner
Copy link
Member

ztanner commented Apr 24, 2024

Hey folks! This is next on my to-do list to look at. Thanks for your patience

@ztanner
Copy link
Member

ztanner commented Apr 25, 2024

@nicolo-tito (and others) -- I want to make sure I'm understanding correctly. If you take the original repro and rename @parallel/[...catchAll] to @parallel/[...testParam] (to match the name of the dynamic page that was matched), then it appears to get the params correctly.

The reason for this is that we currently attempt to match parameters based on the name of the parameter. So since [...catchAll] is technically a different parameter name than [testParam], it doesn't assume they're related.

Is there a caveat to that approach that breaks in other scenarios? Let me know!

EDIT: Ah, looking at the repro from @philwolstenholme, I think I understand a bit better. You essentially want your catch-all parallel route to match any and all params that your page route happens to match. This is an interesting use-case -- off the top of my head, I can't think of any immediate reasons why we'd prevent this. Will investigate a bit and see 👀

@philwolstenholme
Copy link
Contributor

philwolstenholme commented Apr 25, 2024

Ah, looking at the repro from @philwolstenholme, I think I understand a bit better. You essentially want your catch-all parallel route to match any and all params that your page route happens to match

That's exactly it @ztanner :)

Our use case is wanting a place in our app where we can have a site-wide banner component that queries a CMS to see if it should be shown on a particular path or not. We can't do this in a layout.tsx as they don't receive the pathname or search params and don't re-render on a route change. We don't want to do it in a client component using a router hook as it will cause layout shift when the banner either appears or disappears. We don't want to put the component in every single page.tsx file either.

What we'd like to do is to use a parallel route similar to this example, but we have too many routes to want to create directories like @parallel/category/[id], @parallel/product/[slug] etc for each route, hence our interest in using [...catchAll], but being able to get the pathname and search params in order to include them in our GraphQL query to the CMS to 'get banners where path equals "/product/foo"'.

@ztanner
Copy link
Member

ztanner commented Apr 25, 2024

Thanks @philwolstenholme! Working on this here:

@nicolo-tito
Copy link
Author

nicolo-tito commented Apr 26, 2024

Hi @ztanner, thank you for looking into this! I don't have much to add to what @philwolstenholme already said, I'll just add that a very basic use case would be a breadcrumb component, as I wrote here. For that scenario, a catch-all parallel route that receives the same params as the the main route would be perfect, and would also provide a solution for most of the use cases listed in this very old issue #43704

EDIT: sorry, I see now that's already clear to you 😄

Thanks @philwolstenholme! Working on this here:

* [support breadcrumb style catch-all parallel routes #65063](https://github.com/vercel/next.js/pull/65063)

ztanner added a commit that referenced this issue Apr 26, 2024
A common pattern for parallel routes is breadcrumbs. For example, if I
have a lot of dynamic pages, and I want to render a parallel route that
renders as a breadcrumb to enumerate those dynamic params, intuitively
I'd reach for something like `app/@slot/[...allTheThings]/page.tsx`.
Currently however, `[...allTheThings]` would only match params to a
corresponding `app/[allTheThings]/page.tsx`. This makes it difficult to
build the breadcrumbs use-case unless you re-create every single dynamic
page in the parallel route as well.

This adds handling to provide unmatched catch-all routes with all of the
params that are known. For example, if I was on
`/app/[artist]/[album]/[track]`, and I visited `/zack/greatest-hits/1`,
the parallel `@slot` params would receive: `{ allTheThings: ['zack',
'greatest-hits', '1'] }`

Fixes #62539

Closes NEXT-3230
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 May 11, 2024
ztanner added a commit that referenced this issue Oct 4, 2024
A common pattern for parallel routes is breadcrumbs. For example, if I
have a lot of dynamic pages, and I want to render a parallel route that
renders as a breadcrumb to enumerate those dynamic params, intuitively
I'd reach for something like `app/@slot/[...allTheThings]/page.tsx`.
Currently however, `[...allTheThings]` would only match params to a
corresponding `app/[allTheThings]/page.tsx`. This makes it difficult to
build the breadcrumbs use-case unless you re-create every single dynamic
page in the parallel route as well.

This adds handling to provide unmatched catch-all routes with all of the
params that are known. For example, if I was on
`/app/[artist]/[album]/[track]`, and I visited `/zack/greatest-hits/1`,
the parallel `@slot` params would receive: `{ allTheThings: ['zack',
'greatest-hits', '1'] }`

Fixes #62539

Closes NEXT-3230
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug Issue was opened via the bug report template. locked Parallel & Intercepting Routes Related to Parallel and/or Intercepting routes.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants