Intermediate Gatsby, v2

Create Pages with Custom Data Automatically

Jason Lengstorf

Jason Lengstorf

Learn With Jason
Intermediate Gatsby, v2

Check out a free preview of the full Intermediate Gatsby, v2 course

The "Create Pages with Custom Data Automatically" Lesson is part of the full, Intermediate Gatsby, v2 course featured in this preview video. Here's what you'd learn in this lesson:

Jason walks through using Gatsby's file-based routing and the helper package slugify to automatically create pages with custom data. A student's question regarding how to add the page slug as a property in the GraphQL tree is also covered in this segment.


Transcript from the "Create Pages with Custom Data Automatically" Lesson

>> We are going to build out some custom pages, so for the authors, we can do some pretty standard stuff. Now that we've got these authors, I wanna be able to use the just the normal file based like we're gonna use the author slug, and we're gonna build a page.

So, let's start there, and because I didn't add a slug for the books, let's also add a helper called slug phi, which will let us turn the titles of the books into URL slugs, so that we can make pages out of them. So now that I've got this, I'm gonna start well let's create the page first.

So I'm gonna create a new page in here, and we're gonna call this author Slug.js Now note, we're using curly braces here, and then a data type, and the field we wanna use as the path. This is a way to dynamically generate content based on the data in your graph qL layer.

So by creating this, what I'm able to do is Gatsby now will say, hey I see a file, for this author type, do we have authors, do those authors have slug fields? If so, create one page for each author in this array, it's a really powerful flow, It's really nice.

And it lets us get a whole bunch of stuff done, very short order without having to dig into further Gatsby node API's. And then finally we're gonna use this slug phi. What did I import here, that is not what I wanted. I wanted graph qL get slug phi from slug phi.

Okay, so first we're gonna do a query, and when you generate pages from a F data type like this, the way that Gatsby will do it, is it's gonna run a query, it'll build a query that is just for the nodes, the ID and whatever field you used.

So it's gonna generate this query, for the ID in the slug. The ID in the slug will then get passed in the page context, which to refresh your memory there, the page context is, Here. And anything that gets passed here, is available to the page, as the page context Prop, and also, it'll get set as a graph qL variable.

So I have the ability here, let's do author page and this is gonna give us a graph qL variable, which is the ID. And I don't remember what the type of the idea is, so let's hover. And it's an ID type, so I will say we need to get an ID.

And then I wanna get a single author. So let's start the server here actually. So that I can I can build this query in Gatsby instead of guessing at what things are. I think it's gonna yell about my author page that's created and not saved, but that's okay.

Let's get into the graphical, I'm gonna copy paste my query here. All right, and then this is expecting a query variable, which I can grab from down here, so we'll set an ID and our author ID will have to find one of those. So let's, actually maybe start by running this query so that I can get, Here is an author ID, so we'll get this stuff for Nk Jemisin, so here will be our ID, I'm gonna set that value and that's gonna be.

The variable that's set by Gatsby. And then inside of this, I wanna get an author and I want their ID to equal ID. Not equals why did it create that? Okay, inside of that I can get their name and their slug and their books and see let's not filter on that's not what I wanna.

So what I want is, with their name and then their books. For each book the ID, the name, the series, the series order, because we're gonna on each author page, to display their name, and then a list of their books and if they are in a series I wanna say like book one of the whatever series.

So this will be our query and this is what. Expecting type string okay let's do a string. There we go. Okay, so it wants to string glad we checked it because that would have failed otherwise, right? Again, a reason that I really liked this flow of building the query in the browser, instead of trying to just write them by hand is you get to run them and make sure the data comes back the way you expect.

But here we go, so if I get an author with an ID of this string here generated by Gatsby, then I'm able to pull up their name and a list of their books, so let's copy this move into here. All right, and now, when we build out our page, that page is gonna have access to this data, so let's do export default author page, and that has the data.

And in our data, we will have let's start with the basics I guess we're gonna get the concept will be the author and that'll be data author. And then we'll have our books, which will be author dot books, okay. And then we can return Just do a regular old div, I'm gonna do the author name And then before we try to do anything with the books just yet, let's just dump it and look at it.

Okay, so this should put us in pretty good shape, let's get out here and let's look at our 404 page, what don't you like? Gotta call it a function if you're using a function. All right, so here is our list and you can see it generated a thing for each one, so let's jump in here, and we've got a page and that page includes the book information.

So how do we wanna do linking, let's think about the way that we wanna books to be linked. I like my URLs to be descriptive, so if books are related to each other, I want them to tell me that. So for a book like dark matter, it's not part of a series, so I would want the URL to be slash book, slash dark matter.

But for one of these NK Jemisin books that are part of the series, I would actually want that to be included in the URL, so I would want it to be /books, or /book/the broken Earth trilogy/the stones guy. That's the way that I would want that to work so that I know in my head, that I'm looking at a book that is part of a series and I can kinda group those just by looking at URLs, and understand what I'm reading.

So, that means we need to generate our URLs a little bit differently, and I also wanna make sure that these show up in order, like if for whatever reason these got entered as book two went in first and then one and three. I don't want that to show up on the site, so I wanna sort them as well.

So I'm gonna create a little helper function here that we're gonna call sort and extend books, and that's gonna accept our books. And inside of it, we're gonna return the books and we're just gonna do some function stuff with it. So let's do some chaining, well we'll start by sorting, and we'll get book A, book B, and we're gonna return whether the a.seriesOrder is less than the b.seriesOrder.

And I can't remember exactly how this works like, I always have to try this both ways and then see what happens. If you do a minus b goes ascending and if you go b minus a, it goes descending because it's basically if it's a positive value it moves up in the list, and if it's a negative value it moves down in the list I think.

So it's, I don't know that the sword is a little bit confusing but effectively this will give us what we want, It'll put it in series order. Then, we're going to map across each book, and I wanna extend each book. So I'm gonna set up this function here and inside of it, let's get the series first, so if there is a series, we wanna do some stuff.

I want to just create some like display text for this, so we'll say book series and then we'll say, like it's book number one, booked dot series order. So this would be like the broken Earth trilogy book one, book two, book three, okay, that's good. And then if we don't have that, I wanted to just be empty text, so we'll just leave it blank if you don't have a series.

So then we can get a display name and that display name is going to be the book, name and the series. So if it's empty, it'll just be white space we don't care, if it does have a series and it'll be the name of the book, and then in parentheses, the broken earth trilogy book one.

Next, we're gonna set up the book slug. And the book slug is gonna use slug phi, and we just pass in the I wanna to be lowercase. So this will, passing this option in just means that instead of being like capital T, the broken Earth, it'll be the broken earth.

And it converts into a kebab case which is kind of nice, so it's what you would expect in a URL. Finally, we wanna check, we wanna actually build out the path but it's gonna be a different path based on whether or not we have a series or not, so let's start with saying if the book.series is not, no.

Then I wanna set the series slug. Which will be the same general approach slug phi bookseries. And we'll set lower to true. And then down here we will set the path to be, book and then we'll do series slug. And book slug, okay, so that's what we'll get if we have a book with a series.

Now if we don't have a series, We will instead set the path to be just regular old book. And then book's slug. All right, happy with that. And then let's just return our modified books, so we're gonna put back all the regular book things, but then we'll add in the display name and the path as additional fields on our book.

So that means that down here, we just wanna change this out sorts and extend books. Okay, so if we save this, go figure out what I typoed, I pluralized function somehow. There we go. Alright so now we can see that it's been extended each one of these now has a display name, that is doing what we want and it has a path, that includes the the series name and then the regular book name.

And if we go out to one that's not part of a series, we can see the display name is just the book name, and the path is book and the book name. And these are slug phi, and so now we can link to these. So let's update our output then to actually do that, so instead of just dumping this, we're gonna instead we'll create a list and let's tag that, will say Books by [] And inside of this, we'll do a and for each book, we're gonna output some JSX Okay, so we're gonna do a list item, that'll have a key of book that ID.

That's a guaranteed unique string and Gatsby so we can trust it to work, and I wanna bring in the link. That's not coming in from Gatsby, is it? All right, so let me import link, we've already got it, import link from Gatsby, and then we're gonna link to the booked, dot path, and we're gonna show, the book, dot, display name.

All right, and finally we'll just add a link at the bottom to head back to the homepage. Or sorry, to head to an author's page, this doesn't exist, yet we'll build this next. But, rather than having to come back in here and remembering to do it, let's just set it up now.

So do an arrow pointing left, this is an HTML entity, and then we'll go back to all authors. And if I save that, look at it go we got ourselves a page. So if I come in here go to NK Jemisin, here's a list of all those books and if I click to it, we can see that it's taking us to the right place, but we haven't built those pages yet.

So let's build out this authors page. And to do that, we're gonna just do a plain old page, right. And this is what's nice about this is we we did all this work to create custom data, but now we can just build pages the way that we would normally build them, It's really nice.

So we're gonna import everything as react from react, and then we'll get out graph qL and we're gonna need the link as well. Well that helping is not helping is it. From Gatsby, and we're gonna export a const of query, that's gonna be a tag graph qL Query, and this one doesn't need any variables, so we could actually do this as a static query.

But, I don't know why I didn't I think I was just copy pasting thing. So, we'll do it this way all author and inside of our author we're gonna get the nodes, and we want their name and their slug So then we can export our component, which will be the default function called authors page, and that's gonna get some data.

And let's. Pull out those authors, there'll be data.allauthor.nodes. And you know, we should, let's make this simpler like, why overcomplicate this? Let's cut out cognitive loops or cognitive overhead. So instead we're gonna use. Use static query and instead of having to pass things around in props, why don't we just get our data, right out of use static query.

Right when you don't need to use The query, this makes more sense to me, It's hey I wanna use this query, here's the data that I want, give it to me. And then we get our everything else stays the same. So functionally what we just did is identical but, in terms of the the cognitive overhead of somebody reading this code, if they're not familiar with Gatsby.

This doesn't require you to know that the query will get turned into data. So unless you're using again, unless you're working with variables, it's usually easier to just do the simple thing. So let's start by setting up a graph qL fragment because we don't have a JSX fragment instead, so that we don't end up with junky markup that we don't need.

So we'll do a listing of authors, and then we'll do an unordered list and for each author. We're gonna return. Some stuff missing, closing parentheses again. Here we go. This is gonna be a list item, and it's gonna have a key of author dot slug, that's a unique value that we can trust, then we can link to.

And we're gonna make this author dot slug. And we'll put in the author's name, author dot name. Alright, I think I think we've done it. What am I missing here? I'm missing a call Closing curly brace. Let's save it. Let's look at it. All right, we now have our authors pulling in and we have a working website based on our custom data.

So, that's great, but we did throw ourselves a little bit of a curveball here, because now when we look at our books. The books have different URL structure, so we can't just throw in like the book file thing, we're gonna need to build these book links manually these pages are gonna have to get built manually.

>> So, calculating the slug globally each time can become repetitive Is there a way to add that slug as a property in the graph, do you all tree using this page generation technique by using the naming trip, not Create Page hook?
>> 100% Yeah, we could have, added another resolver in here and so for example, the way we did a bio link, we could do a slug and just slug phi, the series and slug phi the book name.

Why I didn't do that, great question. I don't know why I didn't do that, it honestly is probably a better move because then we wouldn't have to calculate it in multiple places, so yeah. If I was gonna refactor this that'd be a great place to refactor this code would be to just add a slug here and then set that as a string and run slug phi in this file, instead of having to do it everywhere.

But, in the interest of not throwing myself too many curveballs cuz we got a lot to cover and I don't wanna run out of time, I'm gonna not do that. So bear with me as we do some little bit of copy pasting around to make this work.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now