Gatsby.js スタティックサイトのチュートリアル Part 6
Gatsby.jsでMDXを使用したブログサイトを作成するチュートリアルのPart6です。前回ブログページにブログポストの一覧を表示できるようにしたので、今回は Gatsby’s Filesystem Route API を使用して各ブログポストのページを作成し、ブログページから各ページにリンクできるようにします。
Gatsby’s File System Route API で動的にルートを作成する
Gatsby’s File System Route API を使用すると一つのページコンポーネントで複数のページを作成できます。独自の記法のファイル名を使うことで動的にルートを作成できます。この機能を使用して各ブログポストのページを作成していきます。
一つのページコンポーネントから複数のルートを作成するにはノードのタイプとURLに使用するフィールドを指定する必要があります。このチュートリアルではノードのタイプはMDXで、URLに使用するフィールドはslugです。GraphiQLでslugを確認しておきます。
取得できるデータは下記のようになります。
{
"data": {
"allMdx": {
"nodes": [
{
"frontmatter": {
"slug": "fifth-post"
}
},
{
"frontmatter": {
"slug": "first-post"
}
},
{
"frontmatter": {
"slug": "fourth-post"
}
},
{
"frontmatter": {
"slug": "second-post"
}
},
{
"frontmatter": {
"slug": "sixth-post"
}
},
{
"frontmatter": {
"slug": "third-post"
}
}
]
}
},
"extensions": {}
}
ブログポストページのテンプレートを作成する
MDXノードのslugフィールドを指定してページを作成する場合は下記のようにファイル名を記述します。
{mdx.frontmatter__slug}.js
ここで、ブログ関係のファイルをまとめるためにファイル構成を変更します。pagesフォルダ内にblogフォルダを作成し、その中にブログ関係のファイルをまとめることで、URLもlocalhost:8000/blog/で始まるURLに統一できます。
まずsrc/pages/blog.jsをsrc/pages/blogフォルダ内に移動し、ファイル名をindex.jsに変更します。フォルダの階層が移動したためimportする階層も変わるため下記のように修正しておきます。
src/pages/blog/index.js
import * as React from 'react'
import { graphql } from 'gatsby'
import Layout from '../../components/layout'
import Seo from '../../components/seo'
const BlogPage = ({ data }) => {
return (
<Layout pageTitle="Blog">
{
data.allMdx.nodes.map((node) => (
<article key={node.id}>
<h2>{node.frontmatter.title}</h2>
<p>Posted: {node.frontmatter.date}</p>
<p>{node.excerpt}</p>
</article>
))
}
</Layout>
)
}
export const query = graphql`
query {
allMdx(sort: { frontmatter: { date: DESC }}) {
nodes {
frontmatter {
title
date(formatString: "MMMM D, YYYY")
}
id
excerpt
}
}
}
`
export const Head = () => <Seo title="Blog" />
export default BlogPage
つづいてブログポストのテンプレートとなるファイルを作成します。GraphiQLで使用するクエリを作成しておきましょう。ブログポストに表示するためにtitleとdateを選択します。ブログページでブログポストのリストを取得する際はallMdxフィールドを選択しましたが、今回は単一のファイルを取得するためmdxフィールドを選択します。
指定のブログポストを取得するためのクエリにはクエリ変数(query variables)を使用します。
mdx → id → eq: と選択し$idと打ちます。クォーテーションマークがついてしまうので手動で削除します。frontmatter内のtitleとdateを選択しdateのformatStringを指定します。クエリ変数($id)の引数を指定するためクエリ名の横に($id: String)と記載すれば完成です。
クエリ変数を指定して、データが取得できるか確認しておきます。GraphiQLの真ん中のペインの下のほうの"Variables"の文字を押すと変数を入力できるスペースが開くので、JSON形式で記載します。クエリを実行するとデータを取得できていることが確認できます。
ちなみにidを確認するには allMdx → nodes → id と選択すれば確認できます。
クエリが作成できたのでブログポストのテンプレートページを作成します。Gatsby’s File System Route API を使用するとidと動的にルートを作成する際に使用するフィールド(今回の場合はfrontmatter__slug)をpropsとして受け渡します。下記のように作成します。
src/pages/blog/ {mdx.frontmatter__slug}.js
import * as React from 'react'
import { graphql } from 'gatsby'
import Layout from '../../components/layout'
import Seo from '../../components/seo'
const BlogPost = ({ data, children }) => {
return (
<Layout pageTitle={data.mdx.frontmatter.title}>
<p>{data.mdx.frontmatter.date}</p>
{children}
</Layout>
)
}
export const query = graphql`
query ($id: String) {
mdx(id: {eq: $id}) {
frontmatter {
title
date(formatString: "MMMM D, YYYY")
}
}
}
`
export const Head = ({ data }) => <Seo title={data.mdx.frontmatter.title} />
export default BlogPost
BlogPostにpropsでdataとchildrenを受け渡します。{children}にMDXファイルの本文が表示されます。Headでもtitleを使用できるようにdataを受け渡しています。
http://localhost:8000/blog/first-post/にアクセスするとコンテンツが表示されているのが確認できます。
ブログページにリンクを追加する
各ブログポストのページが作成できたのでslugを使用してブログページにリンクを追加します。
src/pages/blog/index.js
import * as React from 'react'
import { Link, graphql } from 'gatsby'
import Layout from '../../components/layout'
import Seo from '../../components/seo'
const BlogPage = ({ data }) => {
return (
<Layout pageTitle="Blog">
{
data.allMdx.nodes.map((node) => (
<article key={node.id}>
<h2>
<Link to={`/blog/${node.frontmatter.slug}`}>
{node.frontmatter.title}
</Link>
</h2>
<p>Posted: {node.frontmatter.date}</p>
<p>{node.excerpt}</p>
</article>
))
}
</Layout>
)
}
export const query = graphql`
query {
allMdx(sort: { frontmatter: { date: DESC }}) {
nodes {
frontmatter {
title
date(formatString: "MMMM D, YYYY")
slug
}
id
excerpt
}
}
}
`
export const Head = () => <Seo title="Blog" />
export default BlogPage
Link API を読み込み、リンク先を{/blog/${node.frontmatter.slug}}とします。slugを使用するためクエリにslugを追加しています。localhost:8000/blog/にアクセスすれば各記事のタイトルにリンクがついているのが確認できます。
これでブログページと各ブログポストのページが作成できました。今回は以上です。