DEV Community

Cover image for Creating a Custom React Hook for Gatsby Site Metadata
Scott Spence
Scott Spence

Posted on • Edited on • Originally published at scottspence.com

Creating a Custom React Hook for Gatsby Site Metadata

Photo by Etienne Girardet on Unsplash

Hooks ahoy!

Ok, let's get it on with the new hotness in Reactland, React Hooks!

This is a guide covering using the Gatsby custom React hook for StaticQuery which it is now replacing with useStaticQuery.

If you haven't used Gatsby before StaticQuery is just that, a way to query data in a Gatsby component (i.e. a react component) or a Gatsby page where the query input doesn't change. This is a great use case for data that doesn't change a great deal, like your site metadata.

tl;dr

Here's me trying to even with codesandbox.io whilst I convert some of the Gatsby default starter that's on codesandbox.io to use the useSiteMetadata custom hook.

Using codesandbox.io we take a look at implementing a custom react hook for getting site metadata in Gatsby.

Here's a video:

The StaticQuery component uses the render props pattern, which means it takes in a function and returns/renders based off of that.

I have detailed this pattern before in a post about using the react context api, it's a component that you pass a function to, to render a component.

Think of it like this:

<Component>
 {() => ()}
</Component>
Enter fullscreen mode Exit fullscreen mode

The first parenthesis is the arguments/variables and the second is what gets rendered, so in the case of the Gatsby StaticQuery you pass a query with a graphql tag and then the data that comes back from that is what is used in the render of that component. So you have your wrapping component that returns and renders a child component, like this.

<WrappingComponent>
  {args => <ComponentToRender propsForComponent={args.propNeeded} />}
</WrappingComponent>
Enter fullscreen mode Exit fullscreen mode

Here's a cut down version of the StaticQuery component being used in the Gatsby default starter on codesandbox.io

I've taken out the styling to make it a bit shorter:

const Layout = ({ children }) => (
  <StaticQuery
    query={graphql`
      query SiteTitleQuery {
        site {
          siteMetadata {
            title
          }
        }
      }
    `}
    render={data => (
      <>
        <Header siteTitle={data.site.siteMetadata.title} />
        <div>
          <main>{children}</main>
          <footer />
        </div>
      </>
    )}
  />
)

export default Layout
Enter fullscreen mode Exit fullscreen mode

The StaticQuery takes in two props, the query and what you want to render with render, this is where you can destructure the data you need out of the data prop returned from the query.

I was never really a fan of doing it that way so I adopted a similar pattern but with the component contained on it's own and then added to the StaticQuery separately. Like this:

const Layout = ({ children, data }) => (
  <>
    <Header siteTitle={data.site.siteMetadata.title} />
    <div>
      <main>{children}</main>
      <footer />
    </div>
  </>
)

export default props => (
  <StaticQuery
    query={graphql`
      query SiteTitleQuery {
        site {
          siteMetadata {
            title
          }
        }
      }
    `}
    render={data => <Layout data={data} {...props} />}
  />
)
Enter fullscreen mode Exit fullscreen mode

I found this more acceptable because you didn't have to have all the code bunched into the StaticQuery component.

That all make sense?

Good, now forget about all of that! It's time to use the new useStaticQuery hotness in Gatsby. 💪

Versions:

This guide is being used with the following dependency versions.

  • gatsby: 2.1.31
  • react: 16.8.4
  • react-dom: 16.8.4

You can also check out the example code.


The Gatsby documentation covers the use of it and also how to make your own custom react hook to use useStaticQuery, here's the one I use in the video.

useSiteMetadata.js

import { graphql, useStaticQuery } from 'gatsby'

const useSiteMetadata = () => {
  const { site } = useStaticQuery(
    graphql`
      query SITE_METADATA_QUERY {
        site {
          siteMetadata {
            title
            description
            author
          }
        }
      }
    `
  )
  return site.siteMetadata
}

export default useSiteMetadata
Enter fullscreen mode Exit fullscreen mode

This can now be implemented in the rest of the code as a function call:

const { title, description, author } = useSiteMetadata()
Enter fullscreen mode Exit fullscreen mode

Let's implement it!

In the layout component import the useSiteMetadata hook then we can go about removing the StaticQuery component and destructuring title from the useSiteMetadata hook.

It should look something like this, I have taken the styling out for brevity:

import React from 'react'
import PropTypes from 'prop-types'
import useSiteMetadata from './useSiteMetadata'

import Header from './header'
import './layout.css'

const Layout = ({ children }) => {
  const { title } = useSiteMetadata()
  return (
    <>
      <Header siteTitle={title} />
      <div>
        <main>{children}</main>
        <footer>
          © {new Date().getFullYear()}, Built with
          {` `}
          <a href="https://www.gatsbyjs.org">Gatsby</a>
        </footer>
      </div>
    </>
  )
}
Layout.propTypes = {
  children: PropTypes.node.isRequired
}

export default Layout
Enter fullscreen mode Exit fullscreen mode

Here's the comparison:

compared layout component

On now to the seo component, same again, remove StaticQuery and use useSiteMetadata in its place.

Here's the comparison:

compared seo component

If you want to check out the code the example is available here: example code

Wrap up!

That's it! Wh have gone from using the awesome StaticQuery render props pattern used in Gatsby over to the even more awesome useStaticQuery React hooks, hook.

Thanks for reading 🙏

Please take a look at my other content if you enjoyed this.

Follow me on Twitter or Ask Me Anything on GitHub.

Top comments (3)

Collapse
 
tvanantwerp profile image
Tom VanAntwerp

Love this!

I really hated the way StaticQuery was typically written--it was a real turn-off for using Gatsby. I've much preferred the useStaticQuery hook, and I really like making a custom hook for site metadata! (Gatsby's queries are sooooo verbose...)

Collapse
 
spences10 profile image
Scott Spence

Thanks @tvanantwerp ♥️

I really quite liked the render props pattern for not so deeply nested components.

When using it for things like Apollo it does get quite hairy!🙃

Collapse
 
alextaxiera profile image
Alex Taxiera

Great stuff, I've been using the component not knowing about the hook! Game changer.