How to create a component in React with Gatsby and GraphQL

📅 November 20, 2018

👷 Chris Power

This blog and website are built on React using a static site framework called Gatsby. Recently, I wanted to add a new component to this site to display the latest 3 blog posts on the index page (hey, this may be one of the blog posts being diplayed right now!). I thought this would be a great opportunity to show what its like to make a React component in a Gatsby site, along with a little GraphQL work. We create a new component in our site, grab some data with GraphQL, and display it all on the home page! Alright, enough about me, lets get to business. clears throat.

Here is the video



Can’t watch a video? Here’s a recap

Gatsby is a static site generator built using React. With Gatsby, you get the power and flexibility of React, while enjoying the benefits of a static website. Gatsby bundles up a lot of great technologies to get you started with your static website: server side rendering, a vibrant plugin ecosystem, and multiple starter kits. With Gatsby, you also get a fun querying technology called GraphQL. We won’t touch on too much information about GraphQL in this post, but we will brush over it slightly — as if we were dancing with it, and didn’t want to be too rude.

Part 1. Start with some inline code

When building a new component, sometimes I like to write the code inline, just to prove out the concept of what I want to do. Lets start by writing our three blog posts in a variable (don’t worry, we’ll actually fetch the data later with GraphQL). We assume we’ll have a title and an excerpt for these posts:

const someArrayOfPosts = [
  { title: 'some title for post 1', excerpt: 'this is an excerpt for post one' },
  { title: 'some title for post 2', excerpt: 'this is an excerpt for post two' },
  { title: 'some title for post 3', excerpt: 'this is an excerpt for post three' }
]

Then, lets display these posts somewhere in a render function:

{someArrayOfPosts.map(post => (
  <div class="card">
    <div class="card-title">
      {post.title}
    </div>
    <div class="card-body">
      {post.excerpt}
    </div>
  </div>
))}

Great! You now have three posts displaying somewhere.

Part 2: Extract that code into a component

Lets now create a component with the simple code we just inline’d. In my setup, I write a component to a file like: src/components/ComponentName/index.js. So lets create a new component:

import React from 'react';
const { Component } = React;

class BlogPostPreview extends Component {
  render() {
    const { title, excerpt } = this.props;

    return (
      <div className="col-12 col-md-4 mb-4">
        <div className="card blog-post-preview">
          <div className="card-header font-weight-bold">
            {title}
          </div>
          <div className="card-body text-left">
            {excerpt}
          </div>
        </div>
      </div>
    );
  }
};

export default BlogPostPreview;

I’m expecting that we pass in our title and excerpt in as props. With this component created, lets replace our previous inline’d code in our home page:

import BlogPostPreview from '../components/BlogPostPreview';

then later…

{posts.map(post => (
  <BlogPostPreview
    title={post.title}
    excerpt={post.excerpt}
  />
))}

Cool! We’re getting somewhere

Part 3: Fetch posts with GraphQL and use the data for our component

Now we want to fetch the posts with the GraphQL server built into Gatsby. To do this, we need to add a query to the index page where we’re rendering these posts:

export const pageQuery = graphql`
  query PostPreviewQuery {
    allMarkdownRemark(sort: { fields: [frontmatter___date], order: DESC }, limit: 3) {
      edges {
        node {
          excerpt
          fields {
            slug
          }
          frontmatter {
            title
          }
        }
      }
    }
  }
`

I haven’t checked the docs, but I assume pageQuery is something Gatsby hooks into, in order to run a query on a page. We name this query PostPreviewQuery, we sort by our frontmatter date. and we limit our post count to 3.

Quick note about that frontmatter stuff: We are grabbing markdown posts stored in pages/blog/PostTitle/post.md. These markdown files have a structure at the top describing their date, title, and image. This structure is called frontmatter, and the gatsby transformer remark package helps us query this frontmatter.

our page query returns posts in a format like this:

[
 { node: { data } }
]

So now we can replace our data passed into the component with the new posts from our GraphQL query:

const posts = get(this, 'props.data.allMarkdownRemark.edges');

{posts.map(post => (
  <BlogPostPreview
    title={post.node.frontmatter.title}
    excerpt={post.node.excerpt}
  />
))}

And there you have it. A new component rendering data you grabbed from GraphQL.