Creating a Custom React Hook for Gatsby Site Metadata
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:
1<Component>2 {() => ()}3</Component>
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.
1<WrappingComponent>2 {args => <ComponentToRender propsForComponent={args.propNeeded} />}3</WrappingComponent>
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:
1const Layout = ({ children }) => (2 <StaticQuery3 query={graphql`4 query SiteTitleQuery {5 site {6 siteMetadata {7 title8 }9 }10 }11 `}12 render={data => (13 <>14 <Header siteTitle={data.site.siteMetadata.title} />15 <div>16 <main>{children}</main>17 <footer />18 </div>19 </>20 )}21 />22)2324export default Layout
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:
1const Layout = ({ children, data }) => (2 <>3 <Header siteTitle={data.site.siteMetadata.title} />4 <div>5 <main>{children}</main>6 <footer />7 </div>8 </>9)1011export default props => (12 <StaticQuery13 query={graphql`14 query SiteTitleQuery {15 site {16 siteMetadata {17 title18 }19 }20 }21 `}22 render={data => <Layout data={data} {...props} />}23 />24)
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
1import { graphql, useStaticQuery } from 'gatsby'23const useSiteMetadata = () => {4 const { site } = useStaticQuery(5 graphql`6 query SITE_METADATA_QUERY {7 site {8 siteMetadata {9 title10 description11 author12 }13 }14 }15 `16 )17 return site.siteMetadata18}1920export default useSiteMetadata
This can now be implemented in the rest of the code as a function call:
1const { title, description, author } = useSiteMetadata()
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:
1import React from 'react'2import PropTypes from 'prop-types'3import useSiteMetadata from './useSiteMetadata'45import Header from './header'6import './layout.css'78const Layout = ({ children }) => {9 const { title } = useSiteMetadata()10 return (11 <>12 <Header siteTitle={title} />13 <div>14 <main>{children}</main>15 <footer>16 © {new Date().getFullYear()}, Built with17 {` `}18 <a href="https://www.gatsbyjs.org">Gatsby</a>19 </footer>20 </div>21 </>22 )23}24Layout.propTypes = {25 children: PropTypes.node.isRequired,26}2728export default Layout
Here's the comparison:
On now to the seo
component, same again, remove StaticQuery
and
use useSiteMetadata
in it's place.
Here's the comparison:
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.