Hi. I am using NextJs 14 with app router. I have set up prismic in my project and following this tutorial to add a navigation menu.
Here is my main layout.tsx
file:
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en" className={`${lato.variable}`}>
<body>
<LandingHeader />
<ThemeProvider attribute="class">{children}</ThemeProvider>
</body>
</html>
);
}
and inside my LandingHeader
component, I am trying to add navigation items. The thing is that my LandingHeader
needs to be a client component since I have some useState
to switch between a hamburger icon (mobile) to desktop full navigation menu. Here is part of this file:
const LandingHeader = async () => {
const client = createClient();
const settings = await client.getSingle("settings");
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
return (
<header>
<nav
className="flex items-center justify-between p-6 lg:px-8"
aria-label="Global"
>
<div className="flex lg:flex-1">
<a href="#" className="-m-1.5 p-1.5">
<span className="sr-only">Your Company</span>
<Link href="/" className="">
<Image src="/logo.svg" alt="" width={325} height={46} />
</Link>
</a>
</div>
<div className="flex lg:hidden">
<button
type="button"
className="-m-2.5 inline-flex items-center justify-center rounded-md p-2.5 text-gray-700"
onClick={() => setMobileMenuOpen(true)}
>
<span className="sr-only">Open main menu</span>
<Menu className="h-6 w-6" aria-hidden="true" />
{/* <Bars3Icon /> */}
</button>
</div>
<div className="hidden lg:flex lg:gap-x-12">
{settings.data.navigation.map((item) => (
<PrismicNextLink field={item.link} key={item.label}>{item.label}</PrismicNextLink>
))}
</div>
<div className="hidden lg:flex lg:flex-1 lg:justify-end">
<a
href="#"
className="text-sm font-semibold leading-6 text-gray-900"
>
Log in <span aria-hidden="true">→</span>
</a>
</div>
</nav>
</header>
);
};
export default LandingHeader;
I need to add "use client"
to this file and then I get a warning/error that it cannot be an async
function. So, it appears that I cannot get the navigation data directly in this component. So, I went back to my layout and converted it into an async
function to pass navigation data as prop to my LandingHeader
:
export default async function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
const client = createClient();
const settings = await client.getSingle("settings");
return (
<html lang="en" className={`${lato.variable}`}>
<body>
<LandingHeader settings= {settings} />
<ThemeProvider attribute="class">{children}</ThemeProvider>
</body>
</html>
);
}
My question is whether this is the best solution and if so, I am having a hard time to receive this prop on my LandingHeader
component.
I tried just receiving as type of any
and kind of worked (still getting some errors) but I want to know how I can get the proper type for this? This is what i have inside the prismicio-types.d.ts file:
export interface SettingsDocumentDataNavigationItem {
link: prismic.LinkField;
label: prismic.KeyTextField;
}
/**
* Content for Settings documents
*/
interface SettingsDocumentData {
site_title: prismic.KeyTextField;
meta_description: prismic.KeyTextField;
og_image: prismic.ImageField<never>;
navigation: prismic.GroupField<Simplify<SettingsDocumentDataNavigationItem>>;
}