React × Next.js 実践開発入門 #7 Dynamic Routesを使う
この講座は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.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.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();
これらのgetStaticPaths
、getStaticProps
によって、それぞれのパスに対応した記事のデータが得られる様になります。最後に、これらのデータを表示するためにコンポーネントの実装を確認しましょう。
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により反映させています。
まとめ
今回は、getStaticPaths
とgetStaticProps
の2つの関数を用いた、Dynamic Routesについて紹介しました。これによって、ブログの個別ページを作成できるようになりました。