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`
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;