July 25, 2020
A component in gatsby only has access to a static query by which it can access data in the siteMetadata
section
of gatsby-config.js
or any hard coded query without passing in a variable. How do you pass dynamic data from GraphQL to this component?
We will learn how to do this by adding keywords to the SEO component of every blog post. These keywords reside in the frontmatter of each blog post.
File content/blog/dir-which-becomes-slug-of-blog-post/index.mdx
:
---title: title of postdate: 'YYYY-MM-DD'keywords: [key1, key2, key3]---
Here is how my project is structured:
.-content. |---assets. | |---image1.jpg. |---blog. |---dir-which-becomes-slug-of-blog-post. |-- index.mdx <--- has frontmatter 'keywords' that get put into graphql.-src. |---components. | |---seo.js <--- SEO component only has access to a StaticQuery,. | accessing siteMetadata from gatsby-config.js or. | a hard coded query in 'allMdx'. | <--- I want access to 'keywords' here for specific blog posts. | to plug it into the <head> tag.. |---templates. | |---blog-post.js <--- createPages API in gatsby-node.js calls. | blog-post.js for every .mdx file. | Can get a variable passed into graphql query. | from gatsby-node.js. |---pages. |---index.js <---LANDING PAGE IS HERE. |---blogindex.js <---Page showing list of all blog posts.-gatsby-config.js.-gatsby-node.js
The SEO component in src/components/seo.js
returns JSX with key=value
pairs
that are plugged into the <head>
html tag of the JSX. React-helmet is a library that adds these key-value
pairs to the <head>
of your html document.
This is simplified version of it for illustrative purposes:
File src/components/seo.js
:
function SEO (){return(<Helmettitle={title} <-- from StaticQuery, accessing siteMetadata for the websitedescription={description} <-- from StaticQuery, accessing siteMetadata for the websitekeywords=??/>)export default SEO
How do we get the keywords into the SEO component? We can achieve this by running a pageQuery in src/templates/blog-post.js
, that pulls the keywords
from the frontmatter of the .mdx file for each blog post. It then creates an SEO component
passing the keywords as props to the SEO component for a specific blog post.
File src/templates/blog-post.js
:
class BlogPostTemplate extends React.Component {render() {const post = this.props.data.mdxreturn(<Layout ...><SEO title={post.frontmatter.title} <--- props,overwrites siteMetadata in SEOdescription={post.excerpt} <--- props,overwrites siteMetadata in SEOkeywords={post.frontmatter.keywords}/> <--- Passed as props to SEO</Layout><h1> {post.frontmatter.title}</h1><p> {post.frontmatter.date} </p><MDXRenderer> {post.body}</MDXRenderer>);}}export default BlogPostTemplateexport const pageQuery = graphql`query($slug: String!) { <--- $slug: a variable that got passed by thecreatePages API in gatsby-node.jssite {siteMetadata {titleauthor}}mdx(fields: { slug: { eq: $slug } }) { <--- $slug: "idexcerpt(pruneLength: 160)frontmatter {titledate(formatString: "MMMM DD, YYYY")keywords <--- Keywords for specific blog post}body}}`
The variable $slug
above would not have been available to a component to use in a StaticQuery.
Here is a good video on an introduction to StaticQuery.
The following is a simplified version of what the SEO component looks like, with the StaticQuery in place:
function SEO({ description, keywords, title, meta }) { <---these coming<--- from props, for a single blog postreturn (<StaticQueryquery={detailsQuery}render={data => {const metaDescription =description || data.site.siteMetadata.descriptionreturn (<HelmethtmlAttributes={{lang,}}title={title}meta={[{name: `description`,content: metaDescription,},{property: `og:title`,content: title,},]//.. other fields....concat((keywords && (keywords.length > 0)) <--- KEYWORDS COMING FROM PROPS? {name: `keywords`,content: keywords.join(`, `),}: []).concat(meta)} //end of concat and meta/> //end of Helmet) //end of return}} //end of render and data/> //end of Static Query) //end of return}export default SEOconst detailsQuery = graphql`query DefaultSEOQuery {site {siteMetadata {titledescriptionauthor}}}`
If I now go to that blog post and inspect the Elements, go to the head section and search for keywords, I find this:
<head><meta name="keywords" content="key1, key2, key3" data-react-helmet="true"></head>