GatsbyJS データからプログラムでページを作成 チュートリアル part.7

このチュートリアルは、ギャツビーのデータレイヤーについてのシリーズの一部です。ここに続く前に、パート4パート5パート6を終えたことを確認してください。

このチュートリアルの内容

前回のチュートリアルでは、マークダウンファイルをクエリしてブログ記事のタイトルと抜粋のリストを生成する素敵なインデックスページを作成しました。しかし、単に抜粋を見るのではなく、マークダウンファイルのための実際のページが必要です。

src/pagesReact コンポーネントを配置することで、ページを作成し続けることができます。しかし、データからプログラムでページを作成する方法を学ぶことができるようになりました。Gatsbyは、多くの静的サイトジェネレーターのようにファイルからページを作成することに限定されません。Gatsbyを使用すると、GraphQLを使用してデータをクエリし、クエリ結果をページにマッピングすることができます。これは本当に強力なアイデアです。このチュートリアルの残りの部分では、その意味合いと使用方法を探っていきます。

始めよう

ページ用のスラッグの作成

スラッグ」とは、ウェブアドレスのユニークな識別部分のことで、https://www.gatsbyjs.org/tutorial/part-seven//tutorial/part-seven のようなページです。

これは「パス」とも呼ばれますが、このチュートリアルでは一貫性を保つために「スラッグ」という用語を使用します。 新しいページを作成するには、2つのステップがあります。
  1. ページの「path」または「slug」を生成します。
  2. ページを作成します。
Note:

多くの場合、データソースはコンテンツのスラッグやパス名を直接提供します - これらのシステム(CMSなど)で作業する場合、マークダウンファイルで行うようにスラッグを自分で作成する必要はありません。

マークダウンページを作成するために、2つのGatsby APIであるonCreateNodecreatePagesを使用する方法を学びます。これらは多くのサイトやプラグインで使用されている2つのAPIです。

GatsbyのAPIをシンプルに実装できるように最善を尽くします。APIを実装するには、gatsby-node.jsからAPI名の関数をエクスポートします。 そこで、ここでやることになります。サイトのルートに、gatsby-node.jsというファイルを作成します。そして、次のように追加します。

gatsby-node.js

exports.onCreateNode = ({ node }) => {
  console.log(node.internal.type)
}

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

開発サーバーを停止して再起動します。そうすると、新しく作成されたかなりの数のノードがターミナルコンソールにログに記録されるのがわかります。

次のセクションでは、このAPIを使用してMarkdownページのスラッグをMarkdownRemarkノードに追加します。

MarkdownRemark ノードのみをログに記録するように関数を変更します。

gatsby-node.js

exports.onCreateNode = ({ node }) => {
  if (node.internal.type === `MarkdownRemark`) {
    console.log(node.internal.type)
  }
}

各マークダウンファイル名を使ってページスラッグを作成したいと思います。ということで、pandas-and-bananas.md/pandas-and-bananas/になります。 しかし、MarkdownRemarkノードからファイル名を取得するにはどうすればいいのでしょうか?ファイルノードには、ディスク上のファイルに関する必要なデータが含まれているため、それを取得するには、"ノードグラフ "を親ファイルノードまで辿る必要があります。 そのためには getNode() ヘルパーを使用します。 onCreateNodeの関数パラメータに追加し、それを呼び出してファイルノードを取得します。

gatsby-node.js

exports.onCreateNode = ({ node, getNode }) => {
  if (node.internal.type === `MarkdownRemark`) {
    const fileNode = getNode(node.parent)
    console.log(`\n`, fileNode.relativePath)
  }
}

開発サーバーを再起動した後、2つのマークダウンファイルの相対パスがターミナル画面に表示されるのがわかるはずです。



あとはナメクジの作成ですね。ファイル名からスラッグを作成するロジックは厄介なので、gatsby-source-filesystem プラグインにはスラッグを作成するための関数が同梱されています。それを使おう

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` }))
  }
}

この関数は、スラッグの作成と一緒に親ファイルノードの検索を行います。開発サーバーを再度実行すると、ターミナルに2つのスラッグがログとして記録されているのがわかるはずです。

これで新しいスラグをMarkdownRemarkノードに直接追加することができるようになりました。ノードに追加したデータは、後でGraphQLを使ってクエリできるので、これは強力です。なので、ページを作る時にはスラスラと手に入るようになっています。

そのためには、API の実装に渡された createNodeField という関数を使用します。この機能を使うと、他のプラグインで作成したノードに追加のフィールドを作成することができます。ノードのオリジナルの作成者のみが直接ノードを変更できます。他のすべてのプラグイン(gatsby-node.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を開くか更新します。次に、この GraphQL クエリを実行して、新しいSlugを確認します。


{
  allMarkdownRemark {
    edges {
      node {
        fields {
          slug
        }
      }
    }
  }
}

これでSlugができたので、ページを作成します。

ページを作る

同じgatsby-node.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))
}

プラグインがページを追加できるようにGatsbyが呼び出すcreatePages APIの実装を追加しました。

チュートリアルのこの部分のイントロダクションで述べたように、プログラムでページを作成するための手順は以下の通りです。
  1. GraphQLでデータを問い合わせる
  2. クエリ結果をページにマップする
上記のコードは、作成したマークダウンスラッグを問い合わせるために付属のgraphql関数を使用しているので、マークダウンからページを作成するための最初のステップです。そして、以下のようなクエリの結果をログアウトしています。



ページを作成するためには、スラッグの他にもう一つ必要なものがあります。ギャツビーのすべてのものと同様に、プログラマティックなページはReactコンポーネントを使用しています。ページを作成する際には、どのコンポーネントを使用するかを指定する必要があります。 src/templatesにディレクトリを作成し、src/templates/blog-post.jsというファイルに以下を追加します。

src/templates/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を更新します。
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 に行くと、新しく作成したページが表示されます。 ちょっと確認してみてください。 なにがつまらないかというと、これはあなたが望んだ結果ではありません。
これで、マークダウン投稿からデータを取り込むことができるようになりました。 src/templates/blog-post.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
      }
    }
  }
`

最後にインデックスページから新しいページへのリンクを張ります。
src/pages/index.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
        }
      }
    }
  }
`
出来た!小さくてもちゃんと動くブログです!

やってみよう!

サイトでもっと遊んでみてください。いくつかのマークダウンファイルを追加してみてください。MarkdownRemarkノードから他のデータをクエリして、フロントページやブログ記事ページに追加することを検討します。

このチュートリアルでは、Gatsbyのデータレイヤーを使ったビルドの基礎を学びました。プラグインを使ってデータをソース化して変換する方法、GraphQLを使ってデータをページにマッピングする方法、そして各ページのデータをクエリで取得するページテンプレートコンポーネントを構築する方法を学びました。

次回のチュートリアル8は?

ギャツビーサイトを構築したところで、次はどこに行くか?
Twitterで「#gatsbytutorial」で検索して、他の人が作ったギャツビーサイトをシェアしてみましょう!
  1. ツイートの際には必ず@gatsbyjsに言及し、ハッシュタグ #gatsbytutorial :) を付けてください。
  2. あなたはいくつかの参考サイトを見てみることができます
  3. その他のプラグインを探す
  4. 他の人がギャツビーを使って何を作っているかを見る
  5. Gatsby APInodes、または GraphQL のドキュメントをチェックしてください。


チュートリアルを進める >>