やりたいこと
Next.js の metadata
は、通常 layout.tsx
や page.tsx
内にて、以下のように生成する。
import { Metadata } from 'next'
// 静的
export const metadata: Metadata = {
title: '...',
}
// 動的
export async function generateMetadata({ params }) {
return {
title: '...',
}
}
via. Metadata Object and generateMetadata Options
ただし、
metadata
の object とgenerateMetadata
関数の export はServer Components
でのみサポートされています。
とあるように、Client Components
では使えない。困る。なんとかしたい。
解決策は、悩むような内容ではないが、何度も悩んでいるような気がするので備忘のため。
あっさり解決策
title タグを return すれば良い。おしまい。
page.tsx
'use client';
export function page({ params }: Props) {
const dynamicTitle = xxxx();
return (
<>
<title>{dynamicTitle}</title>
<main>
your main contents
</main>
</>
);
}
具体例
元となる Server Component なコード
src/app/something/[id]/page.tsx
import { metadata } from 'next';
import { getSomethingById } from '@/server/actions'
type Props = {
params: {
id: string;
};
};
export async function generateMetadata({ params }: Props): Promise<Metadata> {
const something = await getSomethingById(params.id);
return {
title: something.title,
...
}
}
export default async function page({ params }: Props ) {
const something = await getSomethingById(params.id);
return (
<main>
your main contents
</main>
)
}
例えば、こんなものがあったとする。これは Server Component
なので何の問題もないのだが、クリックしたらモダルを表示したいとか、何らかの理由で、Client Component
にする必要がある場合もよくある。
Client Component 化する
src/app/something/[id]/page.tsx
'use client';
import { useEffect, useState } from 'react';
import { getSomethingById } from '@/server/actions'
type Props = {
params: {
id: string;
};
};
export default function page({ params }: Props ) {
const [something, setSomething] = useState<DataType | null>(null);
useEffect(() => {
async function fetchData() {
const data = await getSomethingById(params.id);
setSomething(data);
}
fetchData();
}, [params.id]);
// other client logic here.
if (something) {
return (
<>
<title>{something.title}</title>
<main>
your main contents
</main>
</>
);
} else {
return <div>Loading...</div>;
}
}
すごく大雑把だが、データを取得する際の async/await
は、useEffect
内で行い、state にぶち込む。この「あれ?await できないじゃん」と合わせて、よく悩んでるような気がする。
おわり。