Next.js Discord

Discord Forum

nextjs layout only running on the first render

Answered
Sardinian Shepherd Dog posted this in #help-forum
Open in Discord
Avatar
Sardinian Shepherd DogOP
Hello,

I have a nextjs layout using the app directory and im having an issue where the layout is only rendered on the initial page load. I have a loading state which is being used in a <Suspence> boundary, and it works fine.. but only for the first page render. If I refresh the page using f5, it works fine, every time. However, if I use my navigation bar using nextJs <Link> component, the layout isn't rerendered and the loading state is never output onto the screen. I can verify that the layout is never called by adding some console.logs inside of it. Is this something to do with nextjs caching the layout? If so, how can I fix this?

export default async function Layout({ children, params }: Props) {
  const session = await getServerSession(authOptions);

  return (
    <SidebarProvider>
      <Suspense fallback={<LoadingOverlay />}>
        <main className="w-full p-4">{children}</main>
      </Suspense>
    </SidebarProvider>
  );
}
Answered by Asian black bear
You use the loading.tsx file for that.
View full answer

12 Replies

Avatar
Asian black bear
It is by design. Layouts don't rerender if not necessary and if you have a layout that wraps something and you navigate under that path it doesn't have to rerender.
For instance you can see the root layout for a home page and navigating to to dashboard which has the same parent root layout means that the root layout doesn't get rerendered, it will be reused.
Image
Only the new child layouts and pages get rendered and slotted in.
Avatar
Sardinian Shepherd DogOP
Ohh okay, that makes sense, thank you.

Because of this how would I display the loading state for page renders after the inital load?

When redirecting a user to another page, but still under the same layout the page will fetch content which can take x number of seconds, so i was using a suspense component inside of the layout so I can reuse it for all pages under my (dashboard) directory.

(dashboard)/layout.tsx
export default async function Layout({ children, params }: Props) {
  const session = await getServerSession(authOptions);

  return (
    <SidebarProvider>
      <Suspense fallback={<LoadingOverlay />}>
        <main className="w-full p-4">{children}</main>
      </Suspense>
    </SidebarProvider>
  );
}

(dashboard)/dashboard/page.tsx
export default async function Overview({ params }: Props) {
  await new Promise((resolve) => setTimeout(resolve, 1000)); // fake delay for simplicity

  return (
    <HydrateClient>
      <Modules />
    </HydrateClient>
  );
}

in my page.tsx, I can't add a suspense because the data fetching is happening above it, so it doesn't reach the block to tell the client that something is still being fetched
Avatar
Asian black bear
You use the loading.tsx file for that.
Answer
Avatar
Asian black bear
It will be automatically slotted into the place where the page will end up being.
Using Suspense manually isn't a common usecase
Because Next will add the boundaries itself when it see you're using loading.tsx components
Which is the more idiomatic approach.
Avatar
Sardinian Shepherd DogOP
ohhh okay thank you, ill have a look into switching to this now 🙂
Thank you very much 🙂
Avatar
Asian black bear
You're welcome.