next.js

How can I create dynamic metadata for a user profile page in nextjs 15 when using use client


I'm new to nextjs and trying convert a MERN app to nextjs 15. I'm using the same backend api for I used for the MERN app.

I am trying to generate dynamic metadata in a nextjs 15 app in a user profile page that is using "use client".

My basic /[username] page is:

"use client";
import { useParams } from "next/navigation";
import { useAppSelector } from "../redux";
import { useGetProfileByUsernameQuery } from "@/state/api";

const ProfilePage = () => {
  const { username } = useParams();
  const userInfo = useAppSelector((state) => state.global.userInfo);

  const isMyProfile = userInfo && userInfo?.data?.username === username;

  const user = useGetProfileByUsernameQuery(username);

  const profile = user.status === "fulfilled" ? user.data[0] : "";
  return (
    <div>
      {user.status === "pending" ? (
        <h1>Loading...</h1>
      ) : (
        <h1>{`${profile.firstName} ${profile.lastName}`}</h1>
      )}
    </div>
  );
};

export default ProfilePage;

I tried using the generateMetadata function below:

export async function generateMetadata({ params }) {
  return {
    title: `${params.username}'s profile`,
  };
}

When I add this I get the error

You are attempting to export "generateMetadata" from a component marked with "use client", which is disallowed. Either remove the export, or the "use client" directive.

If I remove the "use client" statement, I can't get the user's profile. I get an error from redux.js saying:

You're importing a component that needs `useRef`

Solution

  • You can refer to this doc

    Both static and dynamic metadata through generateMetadata are only supported in Server Components.

    In your case

    ProfilePage.js

    "use client";
    import { useParams } from "next/navigation";
    import { useAppSelector } from "../redux";
    import { useGetProfileByUsernameQuery } from "@/state/api";
    
    const ProfilePage = () => {
      const { username } = useParams();
      const userInfo = useAppSelector((state) => state.global.userInfo);
    
      const isMyProfile = userInfo && userInfo?.data?.username === username;
    
      const user = useGetProfileByUsernameQuery(username);
    
      const profile = user.status === "fulfilled" ? user.data[0] : "";
      return (
        <div>
          {user.status === "pending" ? (
            <h1>Loading...</h1>
          ) : (
            <h1>{`${profile.firstName} ${profile.lastName}`}</h1>
          )}
        </div>
      );
    };
    
    export default ProfilePage;
    

    username/page.js

    import ProfilePage from './ProfilePage';
    
    export async function generateMetadata({ params }) {
      return {
        title: `${params.username}'s profile`,
      };
    }
    
    export default Page(){
     return <div><ProfilePage/></div>
    }
    

    Just put , and metadata tags anywhere in your component tree, including inside client components. React will automatically detect this and put those tags in for you.

    In profile page add title tag.

    "use client";
    import { useParams } from "next/navigation";
    import { useAppSelector } from "../redux";
    import { useGetProfileByUsernameQuery } from "@/state/api";
    
    const ProfilePage = () => {
      const { username } = useParams();
      const userInfo = useAppSelector((state) => state.global.userInfo);
    
      const isMyProfile = userInfo && userInfo?.data?.username === username;
    
      const user = useGetProfileByUsernameQuery(username);
    
      const profile = user.status === "fulfilled" ? user.data[0] : "";
      return (
        <div>
    <title>{`${profile.firstName} ${profile.lastName}`}</title/>
          {user.status === "pending" ? (
            <h1>Loading...</h1>
          ) : (
            <h1>{`${profile.firstName} ${profile.lastName}`}</h1>
          )}
        </div>
      );
    };
    
    export default ProfilePage;
    

    https://nextjs-faq.com/metadata-client-components#how-do-i-set-dynamic-metadata-that-depends-on-client-side-states