Next.js Discord

Discord Forum

Search parameters disable caching on App Router

Unanswered
American Redstart posted this in #help-forum
Open in Discord
Avatar
American RedstartOP
I am working on an application with search functionality, which I want to cache the generated page for a while (ISR). The problem is that, when I add any logic processing in the page.tsx component, the revalidate cache is disabled.

Below is a version without the search parameters. This way the caching works as expected, setting the cache-control to one minute.

import { cache } from 'react'

import { SearchJobs } from '@/services/jobs/search-jobs'

const fetchJobs = cache(async () => {
  return await SearchJobs.instance.execute({ query })
})

export const revalidate = 60

export default async function HomePage() {
  console.log('BUILDING PAGE /(home)')
  const jobs = await fetchJobs()

  return (
    <main>
      <span>
        Found <strong>{jobs.length}</strong> jobs
      </span>
    </main>
  )
}


However, if I try extracting the query parameter from the props, or try getting it from the headers, the revalidation doesn't work anymore. Now, every time the user access the page (with and without query param) the page is generated, without any caching. Here's an example:

const query = typeof searchParams.q === 'string' ? searchParams.q : searchParams.q?.at(0)
const jobs = await fetchJobs(query)


Caching pages is essential in my application, and unfortunately I am not finding a way to make search works this way. Any help is really appreciated!

8 Replies

Avatar
Eurasian Curlew
This isn't a bug. That is completely intended. searchParams, and headers are dynamic APIs and cannot be known ahead of time so it opts the entire route into dynamic rendering, searchParams will opt the page into dynamic rendering. Hence revalidation won't work because all the data is fresh (outside of the router cache).
Avatar
American RedstartOP
Fuck, this is a problem. Is there a way to cache it besides implementing my own cached? I thought about adding the cache-control header, but even with middleware Next.js removes it because of the revalidate, that's super annoying
Avatar
Eurasian Curlew
One solution you could probably implement depending on your application that I use is Dynamic Routes instead of searchParams, essentially the same thing but instead of searchParams it's just route params and you can use APIs like generateStaticParams to statically generate page(s) and then make your fetch calls based off those params and they'll be memoized since you're using cache so you can just add the revalidate option to that page.tsx
This is the only reason why I perfer dynamic routes instead of searchParams for my use case, cause I don't need/want the dynamic behavior.
Avatar
American RedstartOP
Yeah, unfortunately it's either that or try to hack it somehow with pages router. I'll keep searching and try your solution, thank you very much for the help!
Avatar
Alfonsus Ardani
Why not move the searchparam part to client component and wrap it with suspense