Create Pages in Gatsby Using GraphQL

Jason Lengstorf
InstructorJason Lengstorf
Share this video with your friends

Social Share Links

Send Tweet

Why does Gatsby use GraphQL? This is part 5 of a 5-part series that shows how to create pages in Gatsby, how data becomes hard to manage over time, and how GraphQL helps limit the complexity of data management.

In this video, you’ll generate pages with optimized images using GraphQL queries.

Jason Lengstorf: [0:00] To create pages using GraphQL in Gatsby we need to create a gatsby-node.js. We're going to put that at the root level. We need to export the createPages API. Because we're going to making database calls to GraphQL, we're going to make this an async/await function. It's going to be async, and we'll await things inside of it.

[0:30] The arguments to create pages include our actions. Inside of actions we want to get createPage. We also need to get out graphql, which is a function that allows us to query GraphQL. Inside this function we need to make a graphql query.

[0:48] We're going to store the return value of that inside of results. We get that by awaiting the graphql function, and we're going to pass that a query. The query that we want to pass is allProductsJson, just like we tested in the GraphQL Playground.

[1:06] Then we're going to grab the edges and the node, but all we need for this stage is the slug. This is where GraphQL can be confusing at first, but then it gets really powerful as we go on.

[1:19] I'm going to go through. The first thing that we'll see is that the results come back, there's an error in the data. If I look for if (results.error), then I can do something like this. We'll do console.error('Something went wrong!'). Normally you would do better error handling than that. We're going to keep it simple for the purpose of a demo.

[1:49] The data, this is what contains the result here. We're going to do results.data.allProductsJson, and then go to the edges and we'll do a forEach loop on those. That gives us our edge. Inside of that edge, the product itself is the node inside of that edge.

[2:14] Once we have that product, we can create a page with it, which will be placed at path. We are going to do /product/. Then we'll do ${product.slug}/ and then a component, which will be the template used. It's a React component. We haven't built this yet, but we know where it will be so we can say require.resolve('./src/templates/product-graphql.js').

[2:48] Finally, the context. The context, all we're going to pass through is the slug. The reason that we're only passing through the slug is that that's what we're going to use to look up the product on the product template because we can use GraphQL in Gatsby templates as well. Let's create that. Go to templates/product-graphql.js.

[3:10] Inside, we're going to do two things. We're going to make a graphql query for the product data, and we're going to export a component to be used as the template.

[3:24] First, let's import the things that we're going to need. We're going to import React from 'react'. We're also going to need the graphql helper from 'gatsby'. Finally, we're going to be using Gatsby Image, so we're going to import Gatsby Image as well.

[3:41] We can do two things. We're going to export a constant called query and that uses the tag template literal. That's this graphql`` tag template literal. We'll write that query in a second.

[3:57] Then, we're also going to define our Product component and that is going to be exported as our default. The Product component is what we will use for building the pages, so we export that as the default.

[4:14] Our query needs to pull up the data for a single product. Let's start by testing this in the GraphQL Playground. Instead of all products, we're just going to do a query for productsJson and this requires some filtering. The reason that we do this in the Playground, instead of trying to write these by hand, is that we get these helpful hints from the Playground.

[4:35] As soon as I add my filters, I can see what the options are. I want to go by slug, and then we can choose how we're going to match it. If I hit Option-Space, I can see what my options are. I can check that the slug is equal to something, not equal to something. I can match it against a regular expression or a glob. I can check that it's in or not in.

[4:54] I'm going to use equals because I know what it's going to be and let's do space-socks, because we know that one. Let's just query for the title. If I hit this play button, then I can see over here that we are getting just the Space Socks. Again, I can add the description, and there it is.

[5:13] If I want to do this in here, I can't hard code that space-socks. I need to instead use the slug that we've got. We've talked about earlier that anything in context will be made available to the template as pageContext. We also make it available in Gatsby as a variable in GraphQL. The way that variables work is that here I can set up a slug variable and we can set that to space-socks.

[5:48] To use it, I just have to let it know that this query takes a variable, and that variable is going to be of the type String!. GraphQL variables use the dollar sign to signify what they are, and then we give them a type. String and the exclamation point means that it's required.

[6:05] Then, if I come over here and I replace this with $slug, then I still get that same result, but if I change it to one of our other products -- let's go in here and grab let's say this vintage-purple-tee -- I can put this in, hit that play button and we get a different product.

[6:21] This is what we need because this is going to give us the ability to pull based on the slug, which is what's being sent in through the createPage. Let's drop this in.

[6:33] Like I said, anything that comes into the context here, this will be set as a variable in the graphql query. We can just grab that $slug out and make a query for what we need. We need the title and description. We also need the price, and we need the image.

[6:50] The image, we want the optimized version. We're going to go into childImageSharp. We want the fluid version so it can be available at different widths. We're going to use a GraphQL fragment, which is something that we're not going to talk about in-depth in this lesson.

[7:04] Instead of having to type out everything, which would be src, srcSet, aspect-ratio, etc., we can just use this, which is all of those fields bundled up into one.

[7:15] Down in Product, anything that comes out of this graphql query is going to be made available to us as data. That means that we can grab this product by looking for data.productsJson. This means that we can now just return a regular component that uses data that matches up with these values, title, description, price, etc.

[7:41] We can do a div. We'll add a heading. That heading is going to use product.title. We need an image. This is where we use gatsby-image. Gatsby-image, it uses fluid or fixed. We're using fluid in this case. We're going to do product.image.childImageSharp.fluid. We're going to give it an alt tag just like you would a regular image, so that it's accessible.

[8:12] Then, we're going to add a few styles to make sure that it displays OK on this screen. We're going to make it float left, we're going to add a little bit of marginRight so that it doesn't squish the text together. We're going to make it very narrow, width of 150 so that it is small on our screen.

[8:37] Then, we can do the price, so we'll do product.price. We will display the description as dangerouslySetInnerHTML, and that would be the product.description. We save that.

[8:59] Now, we've got our template ready. It's receiving as data the graphql query. That graphql query is using the slug that was set in context. The power of this is that now we don't have to go back into our Gatsby node if anything changes.

[9:14] If we were to say, change the description to a content field or to add a new field for tags, we would change it in the same place that we use it. That makes it a little easier to track what's going on. We've also got a relationship between our image and the data itself as opposed to having to move around the file system to figure things out.

[9:33] Let's test this by running yarn develop. Once this starts, what we should be able to see is, if we go to localhost:8000/product/space-socks, we can see our socks. That's what we wanted.

[9:58] Let's try the vintage-purple-tee. Vintage purple tee and we've got it. With a little bit of upfront set up we now have a very flexible way of getting data and getting the data in an optimized fashion by using the optimized version of the image that Gatsby plugin Sharp creates for us.

[10:18] We also get this bonus of lazy-loaded images where we can see a low-quality version of the image will show up first. Then it will fade in once the full-size image is loaded. This makes the images feel extremely fast even if we're loading large images on the screen. This is a huge performance boost for our users, especially in image-heavy layouts.