#Cannot export Metadata because Next.Js is saying I'm using "use client" on layout.tsx??

51 messages ยท Page 1 of 1 (latest)

woeful tapir
#
Ecmascript file had an error
  18 | });
  19 |
> 20 | export const metadata: Metadata = {
     |              ^^^^^^^^
  21 |   title: "RblxWork",
  22 |   description:
  23 |     "Test.",

You are attempting to export "metadata" from a component marked with "use client", which is disallowed. Either remove the export, or the "use client" directive. Read more: https://nextjs.org/docs/app/api-reference/directives/use-client

ROOT CAUSE:

  • NavigationLabelsList.tsx (Using "use client")
"use client"
import { usePathname } from "next/navigation";
import { NavigationLabel } from "../WebNavigation/NavigationLabel";
import { useMemo } from "react";

export default function NavigationLabelsList() {
    const pathName = usePathname();
    const isHidden = useMemo(() => pathName === "/sign-up" || pathName === "/login", [pathName]);

    return isHidden ? null : (
        <div className="w-auto h-16 flex items-center space-x-10">
            <NavigationLabel href="/about">Why RblxWork</NavigationLabel>
            <NavigationLabel href="/talent">Find Talent</NavigationLabel>
            <NavigationLabel href="/job-listing">Find Work</NavigationLabel>
            <NavigationLabel href="/news">What's new</NavigationLabel>
            <NavigationLabel href="/plan">Pricing</NavigationLabel>
            <NavigationLabel href="/dashboard">Dashboard</NavigationLabel>
        </div>
    )
}

WHERE ERROR OCCURS: (Server Component)

import type { Metadata } from "next";
import localFont from "next/font/local";

import "./globals.css";
import RblxWorkFooter from "@/UI/Components/RootLayout/RblxWorkFooter";
import RblxWorkNavigation from "@/UI/Components/RootLayout/RblxWorkNavigation";

export const avenirRegular = localFont({
  src: "./Fonts/AvenirLTStd-Medium.woff2",
  weight: "400", // Regular weight
  display: "swap",
});

export const avenirBold = localFont({
  src: "./Fonts/AvenirLTStd-Heavy.woff2",
  weight: "700", // Bold weight
  display: "swap",
});

export const metadata: Metadata = {
  title: "RblxWork",
  description:
    "Test",
  icons: "/Website Resources/Favicon/logo.ico",
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <body className={`${avenirRegular.className} antialiased`}>
          <RblxWorkNavigation />
          {children}
          <RblxWorkFooter />
      </body>
    </html>
  );
}
autumn coralBOT
#

๐Ÿ”Ž This post has been indexed in our web forum and will be seen by search engines so other users can find it outside Discord

๐Ÿ•ต๏ธ Your user profile is private by default and won't be visible to users outside Discord, if you want to be visible in the web forum you can add the "Public Profile" role in id:customize

โœ… You can mark a message as the answer for your post with Right click -> Apps -> Mark Solution
(if you don't see the option, try refreshing Discord with Ctrl + R)

woeful tapir
#

This is SOOOO ODD ๐Ÿ˜ญ

#

The problem is FIXED when you:

  1. Remove the export metadata

OR

  1. Remove the "use client" BUT also remove all client interactivity (not what I WANTED)
#

So I thought: Can server component contain client components, I looked it up and it seems that they can, so I'm CONFUSED!!!!

gleaming horizon
#

your error is due to you having "use effect" at the top instead of "use client", any hook starting with the word "use" requires "use client" directive

woeful tapir
#

I meant to say "use client"

#

And usually it occurs when you try to use the directive "use client", I am not sure why. It's so weird.

#

Just updated the error since I realized it was wrong error lol

#

to be clear: when you remove "use client" in the client component, it gets fixed (along with removing effects)

#

that's something I don't want to do

gleaming horizon
#

You need to use "use client" direct in a component that uses hooks, unless its already being called somewhere that is already a client component.

proven panther
#

You cannot set metadata in the same page of use client because metadata only set in server component. So to set metadata create server component add metadata and then call client component in the server component

torn badger
torn badger
# woeful tapir to be clear: when you remove "use client" in the client component, it gets fixed...

If you remove "use client" that is no longer a Client Component, that's why you need to remove the hooks that require it.

What "use client" directive does is telling the Next.js bundler "send this chunk of code and everything that is owned by this file to the browser".

Next.js treats all components as Server components by default, which means you need to opt out of that in case you need to use client-only features like React State, LifeCycle methods (mount, unmount, etc.), the window object and client-only APIs. Only in these situations you should be tempted to write "use client" at the top of the file, and you should try to do it only on very specific components, not the whole page.

#

So now you have to make a choice depending on your needs:
a) Do you need stateless logic and markup or make use of the server to fetch data or set up metadata (... and more)? =>** Server Components** (default)
b) Do you need interactivity, broswer APIs, State and synchronizing your component to external sources? => Client Components (the *typical *way of writing React)

My recommendations: stick to server components until you need client side features, then make a new file marked with "use client" and create your client component, then you can use these *client *components anywhere in your React tree.

woeful tapir
#

Yep I understood what 'use client" is used for, but I mean that:

  1. Layout.tsx is already a server component, that's the pretty much the root layout that share all UIs (which also export metadata).

  2. NavigationLabelsList.tsx is a part of children in layout.tsx which uses "use client" to use hooks (to get path name, etc etc). So of course I need client interactivity.

Imagine the structure of my project:

Layout.tsx (SERVER COMPONENT)
- RblxWorkNavigation.tsx (SERVER COMPONENT)
-> RblxWorkNavigation.tsx also calls the client component (NavigationLabelsList.tsx)
-> NavigationLabelsList.tsx uses "use client" and try to import hooks

and then that's how the error occurred

#

I was talking about issues with server componenet containing nested component children that might be both client and server.

#

So I thought Layout.tsx cannot contain children that is client component? They all must be server-component only?

woeful tapir
#

I understood the difference between Client Components and Server Components, what I am the most confused about is: It does not work the way I expected to be.

robust violet
woeful tapir
#

the only client component is NavigationLabelsList which is far away from Layout.tsx (root)

#

I am not sure how that only client component can cause issues with metadata (which is done on Layout.tsx)

#

NavigationLabelsList doesn't create or export metadata, only Layout.tsx

#

and it has nested children (which is where NavigationLabelsList.tsx is from)

#

and somehow this happened ๐Ÿคท

#

So I am even thinking this is a bug.

#

because it doesn't work the way client components & server components worked

robust violet
#

oooh i see it now

woeful tapir
#

yes!

#

๐Ÿ™

#

If I remove the only client component, the issue is gone, or I make NavigationLabelsList a server component and remove some effects, the issue is gone.

#

So it's like as if the NextJS is telling me "Your root server component cannot contain a mix of nested client components & server components" ๐Ÿ˜ญ

#

The version of NextJS is: v15.1.6

woeful tapir
#

UPDATE!

It seems that this tiny line is causing the error lol

import { avenirRegular } from "@/app/layout";
import Link from "next/link";

interface NavigationLabelProps {
    children: string
    href: string
}

export function NavigationLabel(props: NavigationLabelProps) {
    return (
        // HERE HERE HERE
        <Link className={`${avenirRegular.className}`} href={props.href}>{ props.children }</Link>
    )
}

This is the sub-componet that is used by NavigationLabelsList.

#

I don't understand HOW Link component can cause this error

#

It looks like making it server-component fixes the issue.

#

by using "use server"

#

Nevermind, this causes fetching waterfall.

woeful tapir
#

Looking even DEEPER into this thing and it seems that removing classname finally removes the problem:

<Link className={``}/> // Removed the classname
#

You might ask where the avenirRegular is coming from. Well it looks like it's coming from layout.tsx which is a server component.

#

So in other word: The client component is trying to import something from server component (layout.tsx)?

#

Is that allowed and is supposed to happen?

#

These on Layout.tsx

export const avenirRegular = localFont({
  src: "./Fonts/AvenirLTStd-Medium.woff2",
  weight: "400", // Regular weight
  display: "swap",
});

export const avenirBold = localFont({
  src: "./Fonts/AvenirLTStd-Heavy.woff2",
  weight: "700", // Bold weight
  display: "swap",
});

export const metadata: Metadata = {
  title: "RblxWork",
  description:
    "Test",
  icons: "/Website Resources/Favicon/logo.ico",
};
#

SOLUTION!!!!

I've finally fixed this issue by moving the exporting fonts outside the server component and made it global and can work with client/server.

#

It looks like anything exported from server component becomes server-thing only.

#

I guess that's it for now.

#

Sadly I've not been able to receive helps from you guys but at least I resolved it.