gatsby入門 チュートリアルをこなす 7. プログラムでデータからページを作成する

# gatsbyの作業履歴
[gatsby入門 チュートリアルをこなす 0.開発環境をセットアップする](https://qiita.com/3S_Laboo/items/a38536ed1fb976303b47)
[gatsby入門 チュートリアルをこなす 1. ギャツビービルディングブロックについて知る（１）](https://qiita.com/3S_Laboo/items/014ca205612f21d830aa)
[gatsby入門 チュートリアルをこなす 1. ギャツビービルディングブロックについて知る（２）](https://qiita.com/3S_Laboo/items/4a0f3fdf42c2aa466ed9)
[gatsby入門 チュートリアルをこなす 2.  ギャツビーのスタイリングの概要](https://qiita.com/3S_Laboo/items/41bb0f5f7cabecedc4c2)
[gatsby入門 チュートリアルをこなす 3. ネストされたレイアウトコンポーネントの作成](https://qiita.com/3S_Laboo/items/cc24aae21b22b936488d)
[gatsby入門 チュートリアルをこなす 4. ギャツビーのデータ](https://qiita.com/3S_Laboo/items/49f04f8c9da62a6058cf)
[gatsby入門 チュートリアルをこなす 5. ソースプラグインとクエリされたデータのレンダリング](https://qiita.com/3S_Laboo/items/c9a9a9c3c1e4d0851e6b)
[gatsby入門 チュートリアルをこなす 6.  変圧器プラグイン※Transformer pluginsのgoogle翻訳](https://qiita.com/3S_Laboo/items/226653c9f91cb3a217c7)
[今回：gatsby入門 チュートリアルをこなす 7. プログラムでデータからページを作成する](https://qiita.com/3S_Laboo/items/f80d2c5a36207af71a01)
[gatsby入門 チュートリアルをこなす 8.  公開するサイトの準備](https://qiita.com/3S_Laboo/items/1f50c15a5eddbde6ad18)
[gatsby入門 ブログ作ってサーバーにアップしてみる](https://qiita.com/3S_Laboo/items/7c3ecb0f409fb143f367)
# チュートリアル
今回実施するgatsbyのチュートリアルはこちら
https://www.gatsbyjs.com/tutorial/part-seven/
チュートリアルの冒頭にこう書かれています。

> Reactコンポーネントをsrc / pagesに配置することで、引き続きページを作成できます。ただし、プログラムからデータからページを作成する方法を学習します。

※google翻訳です。
早速やっていきましょう。
ソースは[前回](https://qiita.com/3S_Laboo/items/226653c9f91cb3a217c7)作ったやつを使用します。
#Programmatically create pages from data
## Creating slugs for pages
マークダウンページを作成するには、onCreateNodeとcreatePagesの2つのGatsby APIを使用します。
gatsby-node.jsを作成し、以下を記述します。

```js:gatsby-node.js
exports.onCreateNode = ({ node }) => {
  console.log(`Node created of type "${node.internal.type}"`)
}
```
チュートリアルはこのように記載されています。

>このonCreateNode関数は、新しいノードが作成（または更新）されるたびにGatsbyによって呼び出されます。

なるほど。
gatsby開発サーバを再起動します。
起動はgatsby developでできます。
![2020-09-06_02h21_53.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567235/e8e0ca21-dff2-50fa-746f-4c1ccfaebc77.jpeg)
なんかログがいっぱい出てその中にマークダウンの文字が。
gatsby-node.jsを修正します。

```js:gatsby-node.js
exports.onCreateNode = ({ node }) => {
  ↓ここから
  if (node.internal.type === `MarkdownRemark`) {
    console.log(node.internal.type)
  }
  ↑ここまで修正
}
```
マークダウンだけログだしするのね。
再起動
![2020-09-06_02h26_55.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567235/7384b69f-7e25-4aae-0c99-eed9524f52b8.jpeg)
出てる出てる
マークダウンファイルのファイル名からURLのパスを作っていきましょう。
。。gatsbyだとパスをslugっていうのか。
gatsby-node.jsを修正

```js:gatsby-node.js
exports.onCreateNode = ({ node, getNode }) => {←ここ修正
  if (node.internal.type === `MarkdownRemark`) {
    const fileNode = getNode(node.parent)←ここ修正
    console.log(`\n`, fileNode.relativePath)←ここ修正
  }
}
```
再起動
![2020-09-06_02h32_44.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567235/1cc16a15-76a8-318f-81aa-9fbd3b2fad91.jpeg)
これか！
ここからgatsby-source-filesystem pluginを使用
gatsby-node.jsを修正

```js:gatsby-node.js
const { createFilePath } = require(`gatsby-source-filesystem`)←ここ追記

exports.onCreateNode = ({ node, getNode }) => {
  if (node.internal.type === `MarkdownRemark`) {
    console.log(createFilePath({ node, getNode, basePath: `pages` }))←ここ修正
  }
}
```
再起動
![2020-09-06_02h36_42.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567235/8b065ed5-8d45-f368-fa04-7be43712e31b.jpeg)
出来てる！
ここからcreateNodeFieldを使用してslug(パス)を作ります。
gatsby-node.jsを修正

```js:gatsby-node.js
const { createFilePath } = require(`gatsby-source-filesystem`)
exports.onCreateNode = ({ node, getNode, actions }) => {←ここ修正
  const { createNodeField } = actions←ここ修正
  if (node.internal.type === `MarkdownRemark`) {
    ↓ここから
    const slug = createFilePath({ node, getNode, basePath: `pages` })
    createNodeField({
      node,
      name: `slug`,
      value: slug,
    })
    ↑ここまで追記
  }
}
```
再起動
GraphiQLで以下を実行

```
query MyQuery {
  allMarkdownRemark {
    edges {
      node {
        fields {
          slug
        }
      }
    }
  }
}
```
![2020-09-06_02h45_04.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567235/6a5ff25e-aefa-733c-4ae2-fc8e60012038.jpeg)
キタコレ！

## Creating pages
ページ作りだ！
gatsby-node.jsを修正

```js:gatsby-node.js
const { createFilePath } = require(`gatsby-source-filesystem`)

exports.onCreateNode = ({ node, getNode, actions }) => {
  const { createNodeField } = actions
  if (node.internal.type === `MarkdownRemark`) {
    const slug = createFilePath({ node, getNode, basePath: `pages` })
    createNodeField({
      node,
      name: `slug`,
      value: slug,
    })
  }
}

↓ここから
exports.createPages = async ({ graphql, actions }) => {
  // **Note:** The graphql function call returns a Promise
  // see: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise for more info
  const result = await graphql(`
    query {
      allMarkdownRemark {
        edges {
          node {
            fields {
              slug
            }
          }
        }
      }
    }
  `)
  console.log(JSON.stringify(result, null, 4))
}
↑ここまで追記
```
この時点でどうなるのかさっぱりわからんが続けよう。
src/templatesディレクトリを作成
src/templates/blog-post.jsを作成し以下を記述

```js:blog-post.js
import React from "react"
import Layout from "../components/layout"

export default function BlogPost() {
  return (
    <Layout>
      <div>Hello blog post</div>
    </Layout>
  )
}
```
gatsby-node.jsを修正

```js:gatsby-node.js
const path = require(`path`)←ここ追記
const { createFilePath } = require(`gatsby-source-filesystem`)

exports.onCreateNode = ({ node, getNode, actions }) => {
  const { createNodeField } = actions
  if (node.internal.type === `MarkdownRemark`) {
    const slug = createFilePath({ node, getNode, basePath: `pages` })
    createNodeField({
      node,
      name: `slug`,
      value: slug,
    })
  }
}

exports.createPages = async ({ graphql, actions }) => {
  const { createPage } = actions←ここ追記
  const result = await graphql(`
    query {
      allMarkdownRemark {
        edges {
          node {
            fields {
              slug
            }
          }
        }
      }
    }
  `)
  ↓ここから
  result.data.allMarkdownRemark.edges.forEach(({ node }) => {
    createPage({
      path: node.fields.slug,
      component: path.resolve(`./src/templates/blog-post.js`),
      context: {
        // Data passed to context is available
        // in page queries as GraphQL variables.
        slug: node.fields.slug,
      },
    })
  })
  ↑ここまで追記
}
```
再起動
以下でアクセス
http://localhost:8000/sdf
※sdfは何でもいい
![2020-09-06_03h00_20.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567235/effbea6c-2f2d-4d8f-d8df-d23443ed640a.jpeg)
あ、パスが出来てる
アクセス
![2020-09-06_03h01_14.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567235/93e60c7f-c8f7-8dd6-16f5-311fd391f95c.jpeg)
マークダウンファイルはまだ出てこない。
なるほど、ちょっとわかったぞ。
gatsby-node.jsのonCreateNodeでマークダウンのファイル名を取得してslug(パス)を作成。
createPagesでそのslugを取得し、繰り返し処理の中でパスとsrc/templates/blog-post.jsを同期させるのね！
つづき！
src/templates/blog-post.jsの修正

```js:src/templates/blog-post.js
import React from "react"
import { graphql } from "gatsby"
import Layout from "../components/layout"

export default function BlogPost({ data }) {
  const post = data.markdownRemark
  return (
    <Layout>
      <div>
        <h1>{post.frontmatter.title}</h1>
        <div dangerouslySetInnerHTML={{ __html: post.html }} />
      </div>
    </Layout>
  )
}

export const query = graphql`
  query($slug: String!) {
    markdownRemark(fields: { slug: { eq: $slug } }) {
      html
      frontmatter {
        title
      }
    }
  }
`
```
うんうん。graphqlでマークダウンのhtml情報を取得してsrc/templates/blog-post.jsに書き込む感じか。
![2020-09-06_03h15_57.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567235/c660417c-e230-4bd8-c64a-bd79ae8f2b08.jpeg)
出来た！
そしてsrc/pages/index.jsを修正

```js:src/pages/index.js
import React from "react"
import { css } from "@emotion/core"
import { Link, graphql } from "gatsby"←ここ修正
import { rhythm } from "../utils/typography"
import Layout from "../components/layout"

export default function Home({ data }) {
  return (
    <Layout>
      <div>
        <h1
          css={css`
            display: inline-block;
            border-bottom: 1px solid;
          `}
        >
          Amazing Pandas Eating Things
        </h1>
        <h4>{data.allMarkdownRemark.totalCount} Posts</h4>
        {data.allMarkdownRemark.edges.map(({ node }) => (
          <div key={node.id}>
            ↓ここから
            <Link
              to={node.fields.slug}
              css={css`
                text-decoration: none;
                color: inherit;
              `}
            >
            ↑ここまで修正
              <h3
                css={css`
                  margin-bottom: ${rhythm(1 / 4)};
                `}
              >
                {node.frontmatter.title}{" "}
                <span
                  css={css`
                    color: #555;
                  `}
                >
                  — {node.frontmatter.date}
                </span>
              </h3>
              <p>{node.excerpt}</p>
            </Link>←ここ修正
          </div>
        ))}
      </div>
    </Layout>
  )
}

export const query = graphql`
  query {
    allMarkdownRemark(sort: { fields: [frontmatter___date], order: DESC }) {
      totalCount
      edges {
        node {
          id
          frontmatter {
            title
            date(formatString: "DD MMMM, YYYY")
          }
          ↓ここから
          fields {
            slug
          }
          ↑ここまで修正
          excerpt
        }
      }
    }
  }
`
```
再起動
index.jsからpostにアクセスできるようになった！
チュートリアルはここまでかな。

これ、src/pages内にmdファイルあるのが気になるから移動できないかしら？
src/mdディレクトリ作成し、mdファイルを移動
![2020-09-06_03h26_25.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567235/b1c55e04-78ff-e069-e0b6-397d3b9d674e.jpeg)
再起動
![2020-09-06_03h27_21.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567235/70cea222-c8a3-7430-1b1d-e79edbfc54ac.jpeg)
うん、問題ないね！
今回はここまで。

ありがとうございました。