0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ことばを学ぶ LEARN GATSBY 週間 #4日目

Last updated at Posted at 2020-04-28

こんにちは!

前回は記事の一覧ページを作成しました.

一日目はこちら

今回は、記事一覧ページと個々の記事のつながりを作りたいと思います.
#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()です.
参考サイト

gatsby-node.js
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"
}

slughow である記事のデータが引き出すことができます.
ポイントはこの部分

(fields: { slug: { eq: $slug } })

eqequal を意味し、$slug は変数を表しています. ここでは QUERY VARIABLES にて、"how" と指定しているので、ここの変数を変えることで、ほしい記事のデータを引き出すことができます.
これをすべての slug でやってみましょう.
設定は gatsby-node.js でします.

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 のなかに書き、それを表示させたいと思います !

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 ページにリンクを追加してみましょう !

#記事一覧ページから記事をみる

bloglist.js
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 に以下を追加してください.
スクロールの出現によるレイアウト崩れをなくします.

header.module.scss
body {
    overflow-y: scroll;
  }

ここまでが一応チュートリアルの基本です !

次回から、タグ機能、ブログリストページの分割などを学びたいと思います.

誤字・脱字・コード間違い等ありましたら、コメントお待ちしております.

ここまで読んでくださってありがとうございました.

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?