~30歳プログラマ歴2年の趣味サイト~
CategoryContactAbout
2020.05.26

【Gatsby.js + TypeScript】useStaticryQueryの使い方

TOP画像

はじめに

Gatsby.jsは本当に便利な静的サイト生成ツールです。 便利なフレームワークではありますが、個人的に一番やっかいなのはQrapgQLではないでしょうか。 使えると便利なのですが他で触る機会が少ないので理解するまでに結構時間がかかります。 その中で今回はuseStaticQueryの使い方を書いていきますので何かの参考になればと思います。 公式ドキュメントはこちらです。

やりたいこと

コンポーネントにGraphQLで取得したデータを渡すこと

開発環境

  • Gatsby.js
  • TypeScript
  • emotion(css-in-jsのフレームワーク)

まずStaticQueryとは

公式ドキュメントより

Gatsby v2 introduces StaticQuery, a new API that allows components to retrieve data via a GraphQL query.

Gatsbyのバージョン2より追加された新しいAPIでコンポーネントがGraphQL経由でデータを取得できるようになります。
なぜこれを使うかというと今までの記述だとページ生成時しかデータを渡すことができずにいて、レイアウトページ等の親コンポーネントから順々にデータを渡す必要がありました。 階層が浅ければいいのですが、何階層も下のコンポーネントにデータを渡すのは一苦労でした。

それを解決するのがStaticQueryです。 つまりどこのコンポーネントでもQraphQLからデータが取れるようになるということです。
さらにStaticQueryの書き方は複数あって、今回はフックであるuseStaticQueryを使用しています。

使い方

さっそく使っていきましょう。 今回はこのサイトのフッター部でも使用している管理者情報にアバターの顔を表示している部分のコードを抜き出しながらやっていきます。 画像データをQraphQL経由で取得をすることとします。

完成画面

importする

useStaticQueryを使用できるようにまずimportします。

import { useStaticQuery, graphql } from 'gatsby'

GraphQLでデータを取得する

GraphQLで取得したデータを変数dataに格納します。 色々やり方はあると思いますがここではfilterでimagesフォルダにあるFileを取得しています。 これだけだと画像データは複数取得できてしまうので、コンポーネントに汎用性を持たせるために後の処理で画像を限定します。

const data: ImageQuery = useStaticQuery(
    graphql`
    query Image{
      allFile(filter: {sourceInstanceName: {eq: "images"}}) {
        edges {
          node {
            id
            relativePath
            sourceInstanceName
            childImageSharp {
              id
              fixed (width: 200,height:200){
                base64
                width
                height
                src
                srcSet
                originalName
              }
            }
          }
        }
      }
    }
    `
  )

画像の限定

親コンポーネントでこのようにImageコンポーネントを呼び出します。

<Image name="avater-face.png" />

nameに画像のファイル名を指定します。

Imageコンポーネント側ではこのpropsによりfindメソッドでファイル名を比較します。

const edge = data.allFile.edges.find(edge => edge.node.relativePath == props.name);

コンポーネントのexport 最後にreturnでgatsby-imagesのImgコンポーネントを返せば完了です。

return (
    <Img fixed={edge.node.childImageSharp.fixed} />
  )

コード全体(Imageコンポーネント)

Image.tsx
import * as React from 'react'
import { useStaticQuery, graphql } from 'gatsby'
import { ImageQuery } from "../../types/graphql-types";
import Img from 'gatsby-image';

interface Props {
  name?: string,
}

const Image: React.FC<Props> = (props) => {
  const data: ImageQuery = useStaticQuery(
    graphql`
    query Image{
      allFile(filter: {sourceInstanceName: {eq: "images"}}) {
        edges {
          node {
            id
            relativePath
            sourceInstanceName
            childImageSharp {
              id
              fixed (width: 200,height:200){
                base64
                width
                height
                src
                srcSet
                originalName
              }
            }
          }
        }
      }
    }
    `
  )
  const edge = data.allFile.edges.find(edge => edge.node.relativePath == props.name);
  return (
    <Img fixed={edge.node.childImageSharp.fixed} />
  )
}
export default Image;

まとめ

gatsby.jsで画像を表示させる処理は他のものに比べてかなりめんどくさいですが、このように汎用コンポーネントにしてやればそれほどめんどくさくなくなります。 ただ、幅や高さの指定をするのが結構めんどくさいのでその辺もっといい感じに書けるようになれるとさらによくなると思います。

愛知県在住。プログラマ歴2年目。自動車部品メーカーにて5年程従事した後に、新規一転プログラマの道へ。

現在はベンチャー企業でシステム開発を行っている。メインの使用言語はC#。フロントもJQueryでやっているがReactへの移行を考えている。 短期目標はプログラミング知識を身に着けて自分一人でサービス開発をする、その後中期目標として5年後までにはゲーム開発会社を起業する。 長期目標は楽しく、楽して人生を送りたい。プログラミングは大好き。

仕事、質問、指摘どんなことでも嬉しいのでコンタクトから連絡いただけるとありがたいです。

Gatsby.js + TypeScript + Netlify