やりたかったこと
以下の要領でパスごとに柔軟にページタイトルを変更させようとしました。
パス | ページタイトル |
---|---|
/ | サイトタイトル |
/articles | 記事一覧 - サイトタイトル |
/article/[id] | [idに紐づく記事のタイトル] - サイトタイトル |
脳内実装イメージ
ここら辺を参考にしました。
こんな感じの実装で良いかな~と考えてました
// Next13以降用意されたMetadata上書き関数
export async function generateMetadata({ params }) {
// 現在パス名を取得
const pathname = usePathname()
// カスタムフックでパス別に適切なタイトルを生成
const title = useBuildPageTitle(pathname, params)
// 上書きしたい部分をreturn
return {
title: title,
}
}
usePathnameをインプットに、動的にgenerateMetadataメソッドのreturnを設定するイメージです。しかし・・・
The metadata object and generateMetadata function exports are only supported in Server Components.
メタデータ オブジェクトと generateMetadata 関数のエクスポートは、Server Components でのみサポートされています。https://nextjs.org/docs/app/api-reference/functions/generate-metadata#generatemetadata-function
Reading the current URL from a Server Component is not supported. This design is intentional to support layout state being preserved across page navigations.
サーバーコンポーネントからの現在のURLの読み取りはサポートされていません。この設計は、ページナビゲーションをまたがるレイアウト状態の保持をサポートするための意図的なものです。https://nextjs.org/docs/app/api-reference/functions/use-pathname
metadata上書き用のgenerateMetadataメソッドはサーバサイドでしか使用できず、逆に現在パスを取得するためのusePathnameメソッドはクライアントサイドでしか使用できない仕様でした・・・。
妥協した実装
export const metadata: Metadata = {
title: {
template: '%s - サイトタイトル',
default: 'サイトタイトル',
},
}
import { Metadata } from 'next'
// 各page.tsxにハードコーディングしていく
export const metadata: Metadata = {
title: '記事一覧',
}
import { Metadata } from 'next'
type Props = {
params: { id: string }
}
// 各page.tsxにハードコーディングしていく
export async function generateMetadata(
{ params }: Props
): Promise<Metadata> {
// 記事IDを取得
const articleId = params.id
// ~略~ params.idを使用して記事データを取得
// 取得したデータから記事タイトルを取得
const articleTitle = response.title
return {
title: articleTitle,
}
}
ドキュメントからのほぼコピペですが、実装は上記のようになりました。
usePathnameでgenerateMetadataの挙動を制御できないため、ドキュメントにあるように、各page.tsxごとに静的にgenerateMetadataメソッドのreturnを設定する必要があります。
共通化して動的にせず各page.tsxにtitleをreturnするためのコードを書く必要があるのは正直かなり気になります・・・。
おわりに
Nextはv13でかなり大きな変更がありました。
ネットに落ちているv12までのコードは動かないことがままあります。
今回の実装も、ネットからコードを拾ってきて10分もあれば動作確認できるだろうとたかをくくっていたところに思わぬ落とし穴がありました・・・。
Nextはドキュメントをしっかり読む力が養われるので、チャレンジし甲斐のあるライブラリだと感じました(無理やりいいように表現)。