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

Using generateStaticParams causes issues with searchParams #49735

Open
1 task done
JamesSingleton opened this issue May 13, 2023 · 15 comments
Open
1 task done

Using generateStaticParams causes issues with searchParams #49735

JamesSingleton opened this issue May 13, 2023 · 15 comments
Labels
area: app App directory (appDir: true) bug Issue was opened via the bug report template.

Comments

@JamesSingleton
Copy link

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: 18.16.0
      npm: 9.5.1
      Yarn: 1.22.19
      pnpm: N/A
    Relevant packages:
      next: 13.4.3-canary.0
      eslint-config-next: 13.4.2
      react: 18.2.0
      react-dom: 18.2.0
      typescript: 5.0.4

Which area(s) of Next.js are affected? (leave empty if unsure)

App directory (appDir: true)

Link to the code that reproduces this issue

https://github.com/JamesSingleton/searchparams-issue-next-13

To Reproduce

  1. Clone the repo
  2. Run npm run dev
  3. Go to localhost:3000
  4. Click on the link that says Go to FCS Category
  5. You will be met with the bug

Describe the Bug

For some reason due to using generateStaticParams, if the page you are going to uses the searchParams param available to the page and generateMetadata functions you will get a Dynamic server usage: searchParams.page

Screenshot 2023-05-12 at 9 09 04 PM

Expected Behavior

Ideally there is no error. I have gone through https://nextjs.org/docs/app/api-reference/functions/generate-static-params#generate-params-from-the-top-down but there is no mention of searchParams.

Which browser are you using? (if relevant)

No response

How are you deploying your application? (if relevant)

No response

@JamesSingleton JamesSingleton added the bug Issue was opened via the bug report template. label May 13, 2023
@github-actions github-actions bot added the area: app App directory (appDir: true) label May 13, 2023
@filipkowal
Copy link

filipkowal commented Jun 27, 2023

I encounter almost the same problem. Using generateStaticParams in the root layout and dynamic = "force-dynamic" in one of the pages results in: Error: Dynamic server usage: force-dynamic.

If I remove the force-dynamic directive, the page should stay dynamic as it uses searchParams but it doesn't.

Is there any solution?

@JamesSingleton
Copy link
Author

@filipkowal, not that I know of at the moment. Maybe @leerob can get some eyes on it as this has been an issue for a couple of months now (it was originally part of the discussion of App dir)

@leerob
Copy link
Member

leerob commented Jun 28, 2023

If you are trying to dynamically read URL search params, this requires the page being dynamic. A statically generate page would not have access to the incoming request where the search parameters are read.

@JamesSingleton
Copy link
Author

Ok maybe a dumb question, is there a way to have both? For example have the main content of the page static but the metadata dynamic? Because usually you want to canonical paginate pages to itself.

@leerob
Copy link
Member

leerob commented Jun 28, 2023

Could you expand more on what you're trying to use the query parameters for in this instance?

@JamesSingleton
Copy link
Author

Yeah, so my paginated pages are ?page=2 for example. In order to self canonical (which if my memory is serving me correctly is the right move), I need that searchParam in generateMetadata in order to do so. I would also like to update the title to reference what page the user is on. This is a common practice with paginated pages.

@filipkowal
Copy link

filipkowal commented Jun 28, 2023

@JamesSingleton

Ok maybe a dumb question, is there a way to have both? For example have the main content of the page static but the metadata dynamic? Because usually you want to canonical paginate pages to itself.

At first, I thought we're having the same problem with the generateStaticParams being in the root layout and a dynamic page inside (which is explained here #49373) but if you are trying to have both generateStaticParams and use searchParams on the same page, the error is a correct outcome. You cannot have both, static and dynamic on one page.

It would be helpful if the linter informed about it.

Have you tried the following approach to pagination though? If you'd like to have statically generated paginated pages, you can have the pagination defined as a route [pageIndex]/page.tsx and instead of using searchParams use params. Url would not be ?page=2 but /2 instead. You can also generate metadata on each individual page.

@JamesSingleton
Copy link
Author

@filipkowal yea that would be nice of the linter to inform you of that because technically nothing breaks in production and if you refresh locally it goes away.

As for you suggestion, Google recommends ?page=n in their documentation about pagination best practices.

Also in my case I have /news/[category]/page.tsx and /news/[category]/[subcategory]/page.tsx so not sure that adding /news/[category]/[pageIndex]/page.tsx and /news/[category]/[subcategory]/[pageIndex].tsx would play nice?

Screenshot 2023-06-28 at 8 29 07 AM

In the production version of this website I have the categories hardcoded as /fcs/page/[page].tsx... But with the switch over to the app directory I took it as an opportunity to redo the logic so that I didn't have to hardcode any of the categories and could pull them all from Sanity. Maybe there is a better way?

I did do some research into competition and

I just didn't want their to be a collision of [subcategory]/page.tsx and [pageIndex]/page.tsx as I believe those would conflict as they are at the same level.

@Jordaneisenburger
Copy link

@JamesSingleton This is the same with cookies and generateStaticParams. As an example:
I'm trying to generateStaticParams all my product pages for an e-commerce shop like so

export function generateStaticParams() {
    return [];
}

This will cause our pages to be statically generated by users visiting the product pages which is great! But now we'd like the price on those PDP's to be dynamic per customer and basically stream them in via a <Suspense > component. After trying multiple different ways of achieving this I came to the conclusion that this is currently not possible.

Reading trough multiple issue on GH like #49373, I noticed that everyone expects to be able to mix static and dynamic components which is not the case, your page either needs to be fully static or will be dynamic.

I noted the following "Good to know" section on https://nextjs.org/docs/app/building-your-application/rendering/static-and-dynamic-rendering stating the following:

"In the future, Next.js will introduce hybrid server-side rendering where layouts and pages in a route can be independently statically or dynamically rendered, instead of the whole route."

@leerob please feel free correct me where I'm wrong.

@JamesSingleton
Copy link
Author

JamesSingleton commented Jul 20, 2023

@Jordaneisenburger yea, I guess I would expect some sort of error to be thrown or warning to persist if it was truly an issue. After diving into it more it makes sense and it would be nice if I could do server components with pagination but with my current setup I can't because I already have a dynamic route. That is why I fell back on ?page=n but was hoping to statically generate those like I previously was getting when I was doing /${hardcodedCategory}/page/n back in the pages directory. However, now that I have restructured my paths to now be dynamic, doing that /page/n isn't possible 😓 so being able to statically generate search params was my attempt around it in an odd way.

Screenshot 2023-07-20 at 8 56 54 AM
this structure doesn't work ☝🏼 just used as a reference

@jsefiani

This comment has been minimized.

@tseppl
Copy link

tseppl commented Apr 4, 2024

My understanding is that currently (v14.1.4) it is not possible to render the same page statically AND dynamically based on the data it will need. For example, if you have a product page and have all the data available during build phase provided by generateStaticParams() (no dynamic variables needed) it should be possible to render the product page statically. After the build, if a product would be added between builds to the database and a user would navigate to this product page, it should be dynamically rendered based on dynamic variables (searchParams and JWT cookies). Now you have to opt for either strategy and this essentially means you have to render all products dynamically.
This could be more clearly stated in the documentation.

Also this should be more clearly stated in the build output, which currently lists the product page “prerendered as static HTML (uses getStaticProps)” even though the page is NOT actually created to the .next directory at all if it has any dynamic variables (searchParams or cookies) - an error should be displayed instead to indicate that the page created during build time. Now you cannot rely on the build output - the only way to make sure is to manually check after the build what actually happened.

The build output also mentions getStaticProps even if you use App dir which does not have this method available, it is generateStaticParams().

Screenshot 2024-04-04 at 12 26 43

@Goodosky
Copy link
Contributor

Goodosky commented May 7, 2024

it is not possible to render the same page statically AND dynamically based on the data it will need. For example, if you have a product page and have all the data available during build phase provided by generateStaticParams() (no dynamic variables needed) it should be possible to render the product page statically.

@tseppl There is a partial solution that allows you to use middleware to separate requests without searchParams (and generate them statically) and requests with searchParams (these must be dynamic).

So, for example:

Check out both versions of the category page (clp and plp) and the middleware.

This is not a complete solution to the problem (I believe that partial prerendering will be), but it always allows a large part of the pages to be statically rendered (and load faster)

@trickreich
Copy link

looks like in next 14.2.4 nothing has changed..
only workaround for us is to add a static route..

CleanShot 2024-06-25 at 11 43 14@2x

@trickreich
Copy link

If you are trying to dynamically read URL search params, this requires the page being dynamic. A statically generate page would not have access to the incoming request where the search parameters are read.

But you could render it with default params.. (for example pagination)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: app App directory (appDir: true) bug Issue was opened via the bug report template.
Projects
None yet
Development

No branches or pull requests

8 participants