Data fetching in Layouts (App Router)
Answered
Rex posted this in #help-forum
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 :
The error :
Thanks,
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?
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 !
What did you pass to Grid?
I did not see Grid in Ur code
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 :
However, if i wrap logo with a div, it works :
Interestingly, if i move the div into my Logo component, the same error happens again... Here is the Logo component :
<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 ?
in a new project
RexOP
From a clean install :
And then
In layout.tsx :
Error :
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 :
Data fecthing is not involved.
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.
Can you wrap the Grid in a new file using "use client"?
RexOP
Turns out, just moving the entire grid to a new Component is enough :
I'm puzzled !
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
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?neither, please create a new post or ask in #discussions if its just a general question