初心者による初心者のためのGatsbyJS覚書9（ブログの記事ページを自動生成する）

#この記事について
この記事はGatsbyJS初心者の新卒２年目が作成しています。
参考資料として書籍を使用していますが、筆者がビギナークラスのため読んでいて「？」となる部分や間違っている箇所もあるかと思います。
参考までに、そして間違えている箇所がありましたらご連絡いただけると嬉しいです。

##Chapter9：ブログの記事ページを自動生成する　備忘録メモ

1.テンプレートを作成する。
2.gatsby-node.jsを作成し、必要な設定を記述する
3.前後の記事へのリンクを設定する
※他のチャプターで記載しているメタデータの設定については割愛します。

###テンプレートを作成する
前チャプターで作成していた`blogpost.js`をコピーし、
src配下に新たに`template`ディレクトリを作成し、その中に`blogpost-template.js`名前を変更して配置します。

###gatsby-node.jsを作成し、必要な設定を記述する
プロジェクトフォルダのルート配下に`gatsby-node.js`を作成します。
ページの自動生成にはGatsby Node　APIのcreatePagesを利用していきます。
[参考サイト](https://www.gatsbyjs.com/docs/creating-and-modifying-pages/)

```js
const path = require("path")

exports.createPages = async({ graphql, actions, reporter }) => {
  const { createPage } = actions
//すべての記事ページの生成に必要なデータを取得する。投稿日（publishDate）で降順（DESC）に並べるよう指定。
  const blogresult = await graphql(`
  query {
    allContentfulBlogPost(sort: {fields: publishDate, order: DESC}) {
      edges {
        node {
          id
          slug
        }
      }
    }
  }
  `)
//クエリでエラーが発生した際のエラーメッセージを設定
  if(blogresult.errors){
    reporter.panicOnBuild(`GraphQLのクエリでエラーがが発生しました。`)
    return
  }
//forEachで各記事のデータを取り出し、ページを生成する。
  blogresult.data.allContentfulBlogPost.edges.forEach(({ node, next, previous }) => {
    createPage({
      path: `/blog/post/${node.slug}/`,　//生成するページのパスを指定
      component: path.resolve(`./src/templates/blogpost-template.js`), //生成に使用するテンプレートを指定
      context: {//指定したオブジェクトはテンプレートへ送られる
        id: node.id,//nodeのidをテンプレートに送る
      },
    })
  })
}
```
`blogpost-template.js`のクエリをこのように書き換えます。

```js
//idが一致した記事のデータを取得する
export const query = graphql`
query ($id: String!) { 
  contentfulBlogPost(id: {eq: $id}) {　
    title
    publishDateJP: publishDate(formatString: "YYYY年MM月DD日")
    publishDate
    category {
      categorySlug
      category
      id
    }
...
```

###前後の記事へのリンクを設定する
GraphQLのallContentfulBlogPost＞edges配下のnextとpreviousを使用します。
`gatsby-node.js`にクエリとコンテキストの内容を追加していきます。

```js
const path = require("path")

exports.createPages = async({ graphql, actions, reporter }) => {
  const { createPage } = actions
  const blogresult = await graphql(`
  query {
    allContentfulBlogPost(sort: {fields: publishDate, order: DESC}) {
      edges {
        node {
          id
          slug
        }
        next { //追加
          title
          slug
        }
        previous {//追加
          title
          slug
        }
      }
    }
  }
  `)
  if(blogresult.errors){
    reporter.panicOnBuild(`GraphQLのクエリでエラーがが発生しました。`)
    return
  }

  blogresult.data.allContentfulBlogPost.edges.forEach(({ node, next, previous }) => {
    createPage({
      path: `/blog/post/${node.slug}/`,
      component: path.resolve(`./src/templates/blogpost-template.js`), 
      context: {
        id: node.id,
        next,//追加
        previous,//追加
      },
    })
  })
}
```
`blogpost-template.js`に前後の記事へのリンクを追加します。
論理演算子`&&`を使用することでcontextで送られてくるnextやpreviousがないとき（最新のブログ・最後のブログ）に
リンクを表示しないようにしています。

```jsx

const BlogPost = ({ data, pageContext,location }) => (
<Layout>
・・・・

<ul className="postlink">
  {pageContext.next &&(
  <li className="prev">
    <Link to={`/blog/post/${pageContext.next.slug}/`} rel="prev">
      <FontAwesomeIcon icon={ faChevronLeft }/>
      <span>{pageContext.next.title}</span>
    </Link>
  </li>
  )}
  {pageContext.previous &&(
  <li className="next">
    <Link to={`/blog/post/${pageContext.previous.slug}/`} rel="next">
      <span>{pageContext.previous.title}</span>
      <FontAwesomeIcon icon={ faChevronRight }/>
    </Link>
  </li>
  )}
</ul>
</Layout>
)
```
このようにリンク完成します。リンクの矢印は他チャプターで解説している
Font Awesomeを使用しています。

![スクリーンショット 2021-09-26 22.09.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281399/84f151e9-40e8-b302-55ef-9ad3e2822b07.png)