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