1
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?

Next.js の Client Components で metadata を動的に生成する

Posted at

やりたいこと

Next.js の metadata は、通常 layout.tsxpage.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 できないじゃん」と合わせて、よく悩んでるような気がする。

おわり。

1
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
1
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?