React × Next.js 実践開発入門 #7 Dynamic Routesを使う

公開日:2022-07-19
React
Next.js

https://www.youtube.com/watch?v=8OJjD6zfeY0

この講座はYouTubeで動画形式でも用意しています。合わせてご覧ください。

はじめに

前回 は、事前レンダリングとデータフェッチについて学習し、Markdownで書かれた記事をWebページに反映させました。今回はDynamic Routesを用いて、ブログの個別のページを作成する方法を学びましょう。

Dynamic Routes

前回説明した静的生成でnext buildによるビルド作業を説明しました。このビルド作業では、データベース等から記事の内容を取得し、対応するページを作成します。例えばfooというIDを持ったページを作る場合、Next.jsで/posts/fooというようなパスでアクセスできる様になります。

これを実現する仕組みがDynamic Routesです。具体的には、まずgetStaticPathsという関数を用いてパスの一覧を生成します。その後、前回用いたgetStaticProps関数によって、パスに対応するデータを生成します。

実装してみる

pages/posts配下に、[id].tsxという名称で個別ページ用のファイルを作成します。[id]という部分は実際には記事のIDが反映される様になります。

ファイル全体は以下を参照してください。

https://github.com/redimpulz/nextjs-react-training-blog/blob/master/pages/posts/%5Bid%5D.tsxhttps://github.com/redimpulz/nextjs-react-training-blog/blob/master/pages/posts/[id].tsx

まずはgetStaticPathsの部分です。getAllPostIds()によって全てのパスを取得しています。この全てのパスを返り値に含めています。

export async function getStaticPaths() {
  const paths = getAllPostIds();
  return {
    paths,
    fallback: false,
  };
}

getAllPostIds()の実装は別ファイルにあります。この中では、記事ディレクトリ内のファイルの一覧をreaddirSyncで取得し、IDの形に直しています。

https://github.com/redimpulz/nextjs-react-training-blog/blob/master/lib/posts.tshttps://github.com/redimpulz/nextjs-react-training-blog/blob/master/lib/posts.ts

続いてgetStaticPropsも見てみましょう。引数にparamsがありますが、これはgetStaticPathsで返した値になっています。このparamsからidを取り出しています。

export async function getStaticProps({ params }: GetStaticPropsContext) {
  const id = typeof params?.id === 'string' ? params.id : '';
  const postData = await getPostData(id);
  return {
    props: {
      postData,
    },
  };
}

記事の内容を取得するgetPostDataは前回より少し分量が増えています。gray-matterの他に、remarkというライブラリを導入しました。remarkは、Markdownの内容をHTMLに変換する機能を持っています。

  const processedContent = await remark()
    .use(html)
    .process(matterResult.content);
  const contentHtml = processedContent.toString();

これらのgetStaticPathsgetStaticPropsによって、それぞれのパスに対応した記事のデータが得られる様になります。最後に、これらのデータを表示するためにコンポーネントの実装を確認しましょう。

export default function Post({
  postData,
}: InferGetServerSidePropsType<typeof getStaticProps>) {
  return (
    <Layout>
      <Head>
        <title>{postData.title}</title>
      </Head>
      <article>
        <h1 className={utilStyles.headingXl}>{postData.title}</h1>
        <div className={utilStyles.lightText}>
          <Date dateString={postData.date} />
        </div>
        <div dangerouslySetInnerHTML={{ __html: postData.contentHtml }} />
      </article>
    </Layout>
  );
}

Headコンポーネントにより、記事のタイトルが表示される様にしています。また、日付をフォーマットして表示するためのDateコンポーネントを作成して追加しています。

記事の本文にあたるHTMLの内容は、dangerouslySetInnerHTMLというPropsにより反映させています。

まとめ

今回は、getStaticPathsgetStaticPropsの2つの関数を用いた、Dynamic Routesについて紹介しました。これによって、ブログの個別ページを作成できるようになりました。