So the problem is I have a product page in which I'm getting metadata for that particular product page from backend i.e. from database using an API. I have to use a custom hook to fetch data from that API, Now the Problem is I can't use that metadata from the "use client" directive.
I can't share my whole code As it's 500+ lines so here's a glimpse what I am trying to do!
"use client"
import React from "react";
import useGetData from "./useGetData";
const Page = () => {
const { data } = useGetData();
return (
<div>
Some use of {data}
</div>
);
}
export default Page;
const GenerateMetaDataTags = () => {
const { propId } = useParams();
const { data, loading, error } = useGetData(propId);
const metaData = {};
data.forEach((ele) => {
metaData[ele.name] = ele.content;
});
if (!loading) {
return metaData;
}
};
export const metadata = GenerateMetaDataTags();
I want this Data to update on the client side after fetching from the database.
I tried a lot of different approaches like using layout.js and all but I have to use hook to get the data from database and the hook will always need the "use client";
So the problem is I have a product page in which I'm getting metadata for that particular product page from backend i.e. from database using an API. I have to use a custom hook to fetch data from that API, Now the Problem is I can't use that metadata from the "use client" directive.
I can't share my whole code As it's 500+ lines so here's a glimpse what I am trying to do!
"use client"
import React from "react";
import useGetData from "./useGetData";
const Page = () => {
const { data } = useGetData();
return (
<div>
Some use of {data}
</div>
);
}
export default Page;
const GenerateMetaDataTags = () => {
const { propId } = useParams();
const { data, loading, error } = useGetData(propId);
const metaData = {};
data.forEach((ele) => {
metaData[ele.name] = ele.content;
});
if (!loading) {
return metaData;
}
};
export const metadata = GenerateMetaDataTags();
I want this Data to update on the client side after fetching from the database.
I tried a lot of different approaches like using layout.js and all but I have to use hook to get the data from database and the hook will always need the "use client";
Share Improve this question edited Feb 9, 2024 at 16:35 VLAZ 29.1k9 gold badges63 silver badges84 bronze badges asked Feb 9, 2024 at 16:34 Shivam SharmaShivam Sharma 4415 silver badges15 bronze badges 2- Why do you need a hook to get data from the database? Can you use a server action instead? This would give you client-side updates if you tag and revalidate your fetch call in the data cache. – PhilB Commented Feb 9, 2024 at 16:40
- Still, It will need a "use client" tag to reflect changes in the page. – Shivam Sharma Commented Feb 9, 2024 at 18:00
4 Answers
Reset to default 5This seems to have gotten easier now with the app router.
You can just add Your dynamic title collected from useState here anywhere in a ponent that has "use client"
Assuming data contains an seoTitle and an seoDescription, this could be done like the following.
Metadata.tsx
interface Props {
seoTitle: string;
seoDescription: string;
}
export default function Metadata({ seoTitle, seoDescription }: Props) {
return (
<>
<title>{seoTitle}</title>
<meta name="description" content={seoDescription} />
</>
);
}
Page.tsx
"use client"
import { useState } from "react";
import useGetData from "./useGetData";
const Page = () => {
const { data } = useGetData();
return (
<>
<Metadata seoTitle={data.seoTitle} seoDescription={data.seoDescription} />
<div>
Some use of {data}
</div>
</>
);
}
As per the code here, you have fetched the meta data in metadata
. Now you might need to populate it in the return of the Page
method. Also consider calling GenerateMetaDataTags()
before the return and consider removing the call export const metadata = GenerateMetaDataTags();
in the last line. When you say metadata, I am assuming it is the data in the meta
tags which goes in the Head
ponent like.
import Head from 'next/head'
...
...
const Page = () => {
const { data } = useGetData();
const metadata = GenerateMetaDataTags();
return (
<>
<Head>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="msapplication-TileColor" content="#000000" />
<meta name="msapplication-config" content="/favicon/browserconfig.xml" />
<meta name="ele1" content={metaData["ele1"]} />
<meta name="ele2" content={metaData["ele2"]} />
</Head>
<SomeComponent>
<div>
Some use of {data}
</div>
</SomeComponent>
</>);
}
...
...
You can read more about rendering for pages router, or for app router.
i'm facing the same problem, i tried several approach without success, i'm using next js 14 and mongodb with several nested routes, so the only clean way to fetch the data is client side ( using "use client" for useeffect ), now all pages work very well except the seo part :) , because if you use 'use client' within the app router you can't use the export const metadata or the .
if they had let the nextseo, the head ponent ... it was very easy to deal with seo
as the docs says you cannot generate metadata in a client ponent.