3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Next.js13でmetadataのtitleをpathを参照して動的に変更しようとしたけど無理そうだった

Last updated at Posted at 2023-12-23

やりたかったこと

以下の要領でパスごとに柔軟にページタイトルを変更させようとしました。

パス ページタイトル
/ サイトタイトル
/articles 記事一覧 - サイトタイトル
/article/[id] [idに紐づく記事のタイトル] - サイトタイトル

脳内実装イメージ

ここら辺を参考にしました。

こんな感じの実装で良いかな~と考えてました

どこかの共通コンポーネント.tsx

// Next13以降用意されたMetadata上書き関数
export async function generateMetadata({ params }) {

  // 現在パス名を取得
  const pathname = usePathname()

  // カスタムフックでパス別に適切なタイトルを生成
  const title = useBuildPageTitle(pathname, params)

  // 上書きしたい部分をreturn
  return {
    title: title,
  }
}

usePathnameをインプットに、動的にgenerateMetadataメソッドのreturnを設定するイメージです。しかし・・・

cap1.PNG

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

cap2.PNG

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メソッドはクライアントサイドでしか使用できない仕様でした・・・。

妥協した実装

app/layout.tsx
export const metadata: Metadata = {
  title: {
    template: '%s - サイトタイトル',
    default: 'サイトタイトル',
  },
}
app/articles/page.tsx
import { Metadata } from 'next'
 
// 各page.tsxにハードコーディングしていく
export const metadata: Metadata = {
  title: '記事一覧',
}
app/article/[id]/page.tsx
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はドキュメントをしっかり読む力が養われるので、チャレンジし甲斐のあるライブラリだと感じました(無理やりいいように表現)。

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?