こんにちは!
前回は記事の一覧ページを作成しました.
一日目はこちら
今回は、記事一覧ページと個々の記事のつながりを作りたいと思います.
#slugを作る
つながりのキーワードはずばり、slug
です.
slug
とは、個々の記事を区別する ID
です.
ここではわかりやすく、 slug
= filename
(記事のファイル名) と設定します.
(記事ファイルは マークダウン
で書かれているので、拡張子が .md
です.)
GraphQL playground
にて以下を実行してみましょう.
query {
allMarkdownRemark {
edges {
node {
internal {
type
}
fileAbsolutePath
}
}
}
}
すると右側に、type
が "MarkdownRemark"
、その絶対パス (fileAbsolutePath) が表示されます.
よって、 slug
を取得するには、今回の場合、記事のファイル名を取得するには、絶対パスの最後を抜き取って、拡張子を消してしまえばいいわけです.
やってみましょう. ページ関係の設定は gatsby-node.js
というファイルに書きます.
幸いにも簡単にできるメソッドがあります ! それが path.basename()
です.
参考サイト
const path = require('path')
module.exports.onCreateNode = ({ node , actions }) => {
const { createNodeField } = actions
if (node.internal.type === 'MarkdownRemark') {
const slug = path.basename(node.fileAbsolutePath , '.md' )
createNodeField({
node,
name: 'slug',
value: slug
})
}
}
本当に slug
ができているか、開発用サーバーを再び立ち上げて、graphQL
で確認してみましょう.
query {
allMarkdownRemark {
edges {
node {
fields{
slug
}
}
}
}
}
実行ボタンを押すと、記事のファイル名がslug
としてずらーっと表示されます.
この slug
を利用して、新しいページを作ってみましょう !
#ページ作成
新しいページを作成するには pages
フォルダにファイルを作れば、そのファイル名をパスとしてページが作成できました. しかし記事が何千もある場合はそのやり方では苦痛です.
そこで、Gatsby
では templates
フォルダを作り、そこに記事の テンプレートを作成し、さきほど作った slug
と 記事のデータ
を対応付けることによって、テンプレートを一つ作るだけで、記事を好きなだけ表示させることができるんです.
やってみましょう.
src
フォルダ内に templates
フォルダを作成し、blog-template.js
ファイルを追加します.
slug
と対応づけるという意味を具体的に graphQL
を使ってみてみましょう.
以下のクエリに加え、
query ( $slug: String! ) {
markdownRemark (fields: { slug: { eq: $slug } }) {
frontmatter {
title
date(formatString: "MMMM DD, YYYY")
}
html
}
}
GraphQL
画面左下の QUERY VARIABLES
に以下を加えると、
{
"slug": "how"
}
slug
が how
である記事のデータが引き出すことができます.
ポイントはこの部分
(fields: { slug: { eq: $slug } })
eq
は equal
を意味し、$slug
は変数を表しています. ここでは QUERY VARIABLES
にて、"how"
と指定しているので、ここの変数を変えることで、ほしい記事のデータを引き出すことができます.
これをすべての slug
でやってみましょう.
設定は gatsby-node.js
でします.
module.exports.createPages = async ({ graphql , actions }) => {
const { createPage } = actions
const blogTemplate = path.resolve('./src/templates/blog-template.js')
const res = await graphql(`
query {
allMarkdownRemark {
edges {
node {
fields {
slug
}
}
}
}
}
`)
res.data.allMarkdownRemark.edges.forEach( ({ node }) => {
createPage({
component: blogTemplate ,
path: `/bloglist/${node.fields.slug}` ,
context: {
slug: node.fields.slug
}
})
})
}
これがやっていることを順に説明すると、
「 まずさきにクエリのデータを res
に格納し、各記事ごとに (forEach
メソッドを利用して)
createpage
関数で、component(どのテンプレートを使う?)、path(パスは?) 、context(ここで定義した slug
が さきほど GraphQL
画面左下の QUERY VARIABLES
で定義した slug
と同じ意味になる) を設定しています 」というわけです.
つまり、あらかじめ各記事ごとに slug
を定義しておき、指定されたパスに、slug
との対応付けにより引き出されるデータを、指定されたテンプレートに表示させています.
いまから、上の文章の「 slug
との対応付けにより引き出されるデータ」を実際にクエリで、blog-template.js
のなかに書き、それを表示させたいと思います !
import React from 'react'
import { graphql } from 'gatsby'
import Layout from '../Layouts/common'
export const query = graphql`
query ( $slug: String! ) {
markdownRemark (fields: { slug: { eq: $slug } }) {
frontmatter {
title
date(formatString: "MMMM DD, YYYY")
}
html
}
}
`
const Blog = (props) => {
return (
<Layout>
<h1>{props.data.markdownRemark.frontmatter.title}</h1>
<p>{props.data.markdownRemark.frontmatter.date}</p>
<div dangerouslySetInnerHTML={{ __html: props.data.markdownRemark.html}}></div>
</Layout>
)
}
export default Blog
slug
との対応付けっていうところが、
(fields: { slug: { eq: $slug } })
ですね ! これでパスを指定すると、その記事に飛べるようになりました!
ページを作っているというより、一枚のページの情報を変えて、あたかも複数のページが存在している風にみせている という点が、createPage
関数の良さですね ! この考え方はまた後に出てきます.
さて、bloglist
ページにリンクを追加してみましょう !
#記事一覧ページから記事をみる
import React from 'react'
import { Link , graphql , useStaticQuery } from 'gatsby'
import Layout from '../Layouts/common'
const BlogList = () => {
const data = useStaticQuery(graphql`
query {
allMarkdownRemark {
edges {
node {
frontmatter {
title
date (formatString: "MMMM DD, YYYY")
}
excerpt
fields{
slug
}
}
}
}
}
`)
return (
<Layout>
<h1>This is BlogList </h1>
<ol>
{data.allMarkdownRemark.edges.map( ({node}) => {
return (
<li key={node.fields.slug}>
<Link to={`/bloglist/${node.fields.slug}`} >
<h2>{node.frontmatter.title}</h2>
<p>{node.frontmatter.date}</p>
</Link>
</li>
)
})}
</ol>
</Layout>
)
}
export default BlogList
これで記事一覧ページから、各記事を見ることができるようになりました !!
※ header.module.scss
に以下を追加してください.
スクロールの出現によるレイアウト崩れをなくします.
body {
overflow-y: scroll;
}
ここまでが一応チュートリアルの基本です !
次回から、タグ機能、ブログリストページの分割などを学びたいと思います.
誤字・脱字・コード間違い等ありましたら、コメントお待ちしております.
ここまで読んでくださってありがとうございました.