Next.js Discord

Discord Forum

How to only re-render server components that *actually changed* on route change

Unanswered
Lilac posted this in #help-forum
Open in Discord
LilacOP
Hi.

Fully describe what you're trying to accomplish
I have a server rendered page.
This page has two URL queryParams that can be set: investorId and dateRange.

I have two server-components in this page.
1. An <InvestorInfo/> component which shows the information of the investor. Uses investorId query param.
2.An <ActivityLog/> which shows what that investor has been doing during a given time. Uses both query params investorId and dateRange.

My problem: When I change the dateRange query param (via useQueryState from a client component nested down) the <InvestorInfo/> component also rerenders, even though it has no dependency on the dateRange query param. For my application, this involves expensive calculations which take a long time to finish, which blocks the relatively cheap rerender of the <ActivityLog/> which is all I want to see change anyways.

Bonus question both of these components are wrapped in a suspense. On first load they show the fallback states, but after changing routes thus triggering a rerender, they dont show the fallback state. EDIT: see this link for answer https://github.com/vercel/next.js/issues/49297#issuecomment-1568557317

Code example

export default async function InvestorPage({
  searchParams,
}: {
  searchParams: Record<string, string | string[] | undefined>;
}) {
  const investorId = parseAsString
    .withDefault("")
    .parseServerSide(searchParams?.investorId);
  const dateRange = parseAsDateRange
    .withDefault("")
    .parseServerSide(searchParams?.investorId); // date range parse implementation
  return (
    <div>
      <Suspense fallback={<p>Loading</p>}>
        <InvestorInfo investorId=investorId} />
      </Suspense>
      <Suspense fallback={<p>Loading</p>}>
        <ActivityLog investorId={investorId} dateRange={dateRange} />
      </Suspense>
    </div>
  );
}

13 Replies

First turn them into client components, in RSCs searchParams are only available through page props which is a mess
It might be improved when we have PPR, and if Next adds a function to get search params dynamically similar to headers() and cookies(), but for now that's only doable with client comps
Then make the expensive component a memoized one (this could be improved by React 19 but right now you have to use memoization for these use case) and get the search params props from the parent
Should solve your issues
also please don't DM contribs for help, your question happens to be interesting and you asked nicely but that's ok only once
LilacOP
Thanks a lot Eric, apologies about the DM - it wont happen again.
LilacOP
By making these components client components I can no longer directly call my server functions.

I tried to find a way to wrap these server components in client components like shown, but I don't think NextJs allows this type of composition...

I think the recommended solution here would be to move the "backend logic" into an API route, but I would like to avoid that if possible. Is there any pattern that gets me out of this, or do I have to go the API route?
PPR + searchParams obtained dynamically could solve that but sadly not there yet
ah ok you need the query params to get the data
then no you need an API route there, PPR is indeed the solution without API route
LilacOP
Thanks so much for the help Eric 🙂 I will be following PPR closely
btw I've asked around and it seems that even with PPR this will be hard to handle
because the problem of search params is the fact that layouts never rerender on client navigation
so even with PPR, it's not sure that we can have a server component that rerenders within a layout that does not
LilacOP
Such a shame. I feel like my use-case is probably quite common but just not an issue for people with fast rendering server components / page