Next.js Discord

Discord Forum

Data fetching in Layouts (App Router)

Answered
Rex posted this in #help-forum
Open in Discord
RexOP
Hi,

Is there a way to fetch data on the server side in Layouts ? For example, if I need to fetch a dynamic navigation or images from a headless CMS ?
I tried to add an async component in my layout but it seems to generate an error :
// app/(public)/layout.tsx
export default async function PublicLayout({ children }: PropsWithChildren) {
    return (
        <div>
             <Logo />
             {children}
        </div>
    )
}

async function Logo() {
    const client = createClient()

    const logo = await client.getSingle('logo')

    return (
        <Image
            src="logo.data.image/src"
        />
    )
}


The error :
Error: Objects are not valid as a React child (found: object with keys {$$typeof, _payload, _init}). If you meant to render a collection of children, use an array instead.


Thanks,
Answered by alfonsus ardani
After reading a bit, that seems like another problem in the rendering part. Are you sure the problem occurs when importing Logocomponent?
View full answer

19 Replies

It's possible to fetch in layout. That seems like another problem when trying to do the fetch
After reading a bit, that seems like another problem in the rendering part. Are you sure the problem occurs when importing Logocomponent?
Answer
RexOP
Yes, and if i use the same component directly in a page it seems to work fine
RexOP
Alright, it seems my component generates this error when nested in a Material UI Grid component, I have no idea why, but data fetching does work well in my layout if I remove the Grid component. Thanks !
RexOP
Yes i tried to post a simplified version and never expected this to be the issue... Here is the code that generates the error :
<Grid xs={4} sm={6}>
    <Logo />
</Grid>


However, if i wrap logo with a div, it works :
<Grid xs={4} sm={6}>
    <div>
        <Logo />
    </div>
</Grid>


Interestingly, if i move the div into my Logo component, the same error happens again... Here is the Logo component :
import { createClient } from '@/prismicio'
import { PrismicNextImage } from '@prismicio/next'

export const PublicSideImage = async () => {
    const client = createClient()

    const publicContent = await client.getSingle('public_content')

    return (
        <PrismicNextImage
            field={publicContent.data.image}
        />
    )
}
Just to be clear, I'm using MUI Grid component :
import Grid from '@mui/material/Unstable_Grid2'
Can you reproduce the bug using Unstable_Grid in Nextjs?
RexOP
What do you mean ? In a page instead of a layout ?
RexOP
From a clean install : npx create-next-app@latest
And then npm install @mui/material @emotion/react @emotion/styled

In layout.tsx :
import Grid2 from "@mui/material/Unstable_Grid2/Grid2";
import "./globals.css";
import type { Metadata } from "next";
import { Inter } from "next/font/google";
import { Logo } from "../Logo";

const inter = Inter({ subsets: ["latin"] });

export const metadata: Metadata = {
  title: "Create Next App",
  description: "Generated by create next app",
};

export default async function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body className={inter.className}>
        <Grid2 container>
          <Grid2 xs={12}>
            <Logo />
          </Grid2>
          <Grid2 xs={12}>{children}</Grid2>
        </Grid2>
      </body>
    </html>
  );
}


Error :
Check your code at layout.tsx:24.
 ⨯ Error: Unsupported Server Component type: undefined
    at stringify (<anonymous>)
 ⨯ Internal error: Error: Objects are not valid as a React child (found: object with keys {$$typeof, _payload, _init}). If you meant to render a collection of children, use an array instead.
Sorry sent it too fast, here is Logo.tsx :
import Image from "next/image";

export const Logo = async () => {
  return <Image src="/logo.svg" height={54} width={192} alt="Test" />;
};


Data fecthing is not involved.
RexOP
Turns out, just moving the entire grid to a new Component is enough :
import Grid2 from "@mui/material/Unstable_Grid2/Grid2";
import { Logo } from "./Logo";

export const Grid = async ({ children }: { children: React.ReactNode }) => {
  <Grid2 container>
    <Grid2 xs={12}>
      <Logo />
    </Grid2>
    <Grid2 xs={12}>{children}</Grid2>
  </Grid2>;
};


I'm puzzled !
is enough for?
RexOP
To fix it
@alfonsus ardani Can you wrap the Grid in a new file using "use client"?
General question: Does 'use client' mean some of the page uses client-side rendering, or does it mean none of it uses server-side rendering?