エンジニアを目指す日常ブログ

日々勉強したことのメモ。独学ですので間違っていたらコメント等で教えてください。

GatsbyのデータレイヤーからgraphQLでデータを取得する

はじめに

Gatsbyでブログを書くためには、1ページずつHTMLを書くわけにもいかないので、記事を書いたデータベースからデータを取得してコンポーネントに組み込む必要がある。

Gatsbyではデータの取得にGraphQLを利用する。

GraphQLでのデータ取得方法の基礎的なやり方をメモする。

参考
システム構成図:GatsbyブログをGatsby Cloudで公開してみた - エンジニアを目指す日常ブログ
GraphQLとは:tomiko0404.hatenablog.com

この記事のゴール

  • GraphQLのクエリ作成方法と、結果の利用方法を理解する。
  • gatasby-config.jsで設定したsiteMetadataのデータをGraphQLで取得し、コンポーネントに反映する。

前回の記事

tomiko0404.hatenablog.com

前提

  • gatsby-starter-blogスターターキットを利用したgatsbyブログを立ち上げ済
  • Vagrantを開発環境として利用
  • Gatsby Cloudで公開済(今回は利用しないので、なくても可)

Gatsbyデータ管理のしくみ

以下の図のように、まず「ソースプラグイン」と呼ばれるプラグインを利用し、データを「データレイヤー」に取り込む。データレイヤーのデータにGraphQL APIでアクセスし、コンポーネント側で利用する。

ソースプラグイン

以下のサイトでgatsby-souce-で検索するとソースプラグインが出てくる。

https://www.gatsbyjs.com/pluginswww.gatsbyjs.com

  • gatsby-source-filesystem
  • gatsby-source-contentful
  • gatsby-source-graphql

等がある。例えば、ヘッドレスCMSの「Contentful」からデータを取得する場合にはgatsby-source-contentfulを使うのが良い。

ソースプラグインを利用したデータの取得方法は後日記載

siteMetadataオブジェクトの取得

gatsby-config.jsmodule.exportsしているデータは、ソースプラグインを利用しなくても自動的にGatasbyのデータレイヤにプルされている。

gatsby-config.jsで設定したsiteMetadataオブジェクトは、GatsbyデータレイヤーからGraphQL APIで取得できる状態になっているので、試しに取得してみる。

GraphQLでのデータ取得

useStaticQuery関数を利用してデータ取得

Aboutページに、siteMetadatatitleを取得して追加してみる。

情報の取得には、今回useStaticQueryを使う。

import { useStaticQuery, graphql } from 'gatsby';

でのインポートと、

    const data = useStaticQuery(graphql`
  // 要求電文
  `)

が必要である。

取得したデータは、通常のオブジェクトと同様

<p>{data.site.siteMetadata.title}</p>

のように利用できる。

src/pages/about.js

import { useStaticQuery, graphql } from 'gatsby';
import * as React from 'react'
import MyLayout from '../components/myLayout';


const About = () => {

    const data = useStaticQuery(graphql`
    query {
      site {
        siteMetadata {
          title
        }
      }
    }
  `)

    console.log(data)

    return (

        <MyLayout pageTitle="このサイトについて">
            <p>{data.site.siteMetadata.title}</p>
            <p>ayです。Gatsbyを利用し作成しています。</p>
            <p>お問い合わせはこちら 03-xxxx-xxxx</p>
        </MyLayout>
    )

}

export default About;

Aboutページに、data.site.siteMetadata.titleを表示することができた。

取得したtitleを&lt;p&gt;タグで表示
取得したtitleを<p>タグで表示

graphql関数を利用したデータ取得

インポート文は以下。

import { graphql } from 'gatsby';

クエリの書き方は以下のようになる。

export const query = graphql`
     //要求電文
`

このように書くと、自動的にコンポーネントprops.dataに値が渡される。

詳細は、以下の記事を参照。

GraphiQLを活用した要求電文の生成

要求電文の生成方法にくせがあるので、GraphiQLというツールを利用する。

こちらも参照:GraphQLって何? - エンジニアを目指す日常ブログ

Gatsbyでは、gatsby developを実行して、

http:localhost:8000/___graphiql

にアクセスすると、GraphiQLでGraphQLデータレイヤーにあるフィールドに対する要求電文と応答電文をテストできる。

以下のように、Gatsbyデータレイヤーで利用できる、クエリのルートフィールドが一覧になっている。

GraphiQLのquery一覧
GraphiQLのquery一覧

右側のDocで、今回使うクエリのsiteを確認すると、

  • 引数
buildTime: DateQueryOperatorInput
children: NodeFilterListInput
host: StringQueryOperatorInput
id: StringQueryOperatorInput
internal: InternalFilterInput
jsxRuntime: StringQueryOperatorInput
parent: NodeFilterInput
pathPrefix: StringQueryOperatorInput
polyfill: BooleanQueryOperatorInput
port: IntQueryOperatorInput
siteMetadata: SiteSiteMetadataFilterInput
  • 応答値の型
Site

となっている。 Site型の構成は、

buildTime(
    difference: String
    formatString: String
    fromNow: Boolean
    locale: String
): Date
siteMetadata: SiteSiteMetadata
port: Int
host: String
polyfill: Boolean
pathPrefix: String
jsxRuntime: String
id: ID!
parent: Node
children: [Node!]!
internal: Internal!

となっている。

siteMetadata: SiteSiteMetadataSiteSiteMetadata型の構成は

title: String
description: String
author: Author
siteUrl: String
social: Social

となる。

これをふまえて、siteツリーを開いていってtitleにチェックを付けると要求電文が出来上がる。

応答電文としてtitleが取得できていることがわかる。

GraphiQLを利用して要求電文の作成
GraphiQLを利用して要求電文の作成

titleには、紫色と青色が2つあるが、紫色のほうは絞り込み条件を設定する際などに使用するものなので、今回は青色にチェックを入れた。

ここで作成した要求電文には、MyQueryという名前がついているが、コンポーネント内で利用するときはその部分は削除することに注意する。

【参考】useStaticQuerygraphqlどちらを使うか

gatsby-starter-blogスターターキットのindex.jsには既にGraphQLのクエリが存在するが、そちらではuseStaticQueryを利用していない。

src/pages/index.js

export const pageQuery = graphql`
  query {
    site {
      siteMetadata {
        title
      }
    }
    allMarkdownRemark(sort: { fields: [frontmatter___date], order: DESC }) {
      nodes {
        excerpt
        fields {
          slug
        }
        frontmatter {
          date(formatString: "MMMM DD, YYYY")
          title
          description
        }
      }
    }
  }
`

以下のサイトに解説があった。

dezanari.com

useStaticQueryを使わない場合のクエリを「ページクエリ」と呼ぶそうで、useStaticQueryコンポーネントの中に書くのに対し、ページクエリはコンポーネントの外に書く。

また、ページクエリは、単独でページになるコンポーネント/pages配下にあるようなコンポーネント)でしか使えないという制約があるらしい。

注意:graphqlのクエリは、1つのコンポーネントに1つしか入れられない

graphqlのクエリは、1つのコンポーネントに1つしか入れられないようだ。

index.jsで同じことを実施すると、エラーになってしまった。 利用しているgatsby-starter-blogスターターキットでは、index.js上に既に完成されたGraphQLのクエリが存在するため、エラーになってしまった。


 ERROR #85910  GRAPHQL

Multiple "root" queries found: "(クエリ名1)" and
"(クエリ名2)".
Only the first ("(クエリ名2)") will be registered.

Instead of:

   1 | query (クエリ名2) {
   2 |   site {
   3 |     #...
   4 |   }
   5 | }
   6 |
   7 | query (クエリ名1) {
   8 |   site {
   9 |     #...
  10 |   }
  11 | }

Do:

  1 | query
(クエリ名1)(クエリ名2) {
  2 |   site {
  3 |     #...
  4 |   }
  5 |   site {
  6 |     #...
  7 |   }
  8 | }

This can happen when you use two page/static queries in one file. Please combine those into one query.
If you're defining multiple components (each with a static query) in one file, you'll need to move each component to its own file.

おわりに

Gatsbyのデータレイヤーに存在するデータをGraphQL APIで取得することができた。

関連記事

つづき