This course has been updated! We now recommend you take the Intermediate Gatsby, v2 course.
Transcript from the "useStaticQuery Hook" Lesson
[00:00:00]
>> I wanna create a table of contents. So I wanna be able to see what else is in the docs. And to do that as kind of a shortcut today, we will just create a component that does that for us. So the way that that works is we're going to get into our components, and let's just create something called table-of-contents.js.
[00:00:26] And inside of that I'm going to, we'll just start out with some style so that we don't have to do that in phases. So we'll set the fragment of jsx. we'll import jsx from the UI. And then we're also going to import graphql. Link so that we can link between the pages, and then a hook that Gatsby gives us called useStaticQquery.
[00:00:52] Now because this is not a template, we don't have access to the page queries or context or variables or anything. So we're gonna use this useStaticQuery. So that we can get data out but it's important to note that we can only do this if you don't need variables.
[00:01:12] You can't, you have to hard code everything and useStaticQuery that's why it's static you don't get dynamic content. So first let's set up our component itself, TableofContents. If I can spell it, that doesn't get any arguments. And we will export that as our default. Inside, we will, as a first step, load our data.
[00:01:42] So let's get the data and that's gonna be the result of useStaticQuery. And we use the graphqL tag to signify that it is indeed a query. And I want to get all Doc's page nodes. And I want the ids so that we can use it as a react key.
[00:02:00] I want the title so that we can have some display text. And I want the path so that we know where to send somebody if they click the link. Once we've got that data, it's going to come in and be stored in this data prop. Gatsby will do this at build time actually.
[00:02:16] So we don't need to await it or anything. It just, as far as the component is concerned when it runs in the browser, that data will already exist. Then we can for convenience, let's rename pages and we'll get data.allDocs.page.nodes, then we can return a thing. So the thing that we want to return Is, we'll give it a div in case we wanna style it or add some borders or something around it.
[00:02:48] We're not gonna do that for now, but we wanna leave that door open. Let's add a heading to it. So we'll say Explore the Docs. And then we'll just show these in a list. So let's map over our pages. And for each one, we're gonna get out that id, path and title.
[00:03:10] And we can return, an Li will set the key to the id. And then inside of that, we're gonna use a link, and I want that to link to the path. And I wanna give it some styles. So the styles that I want are actually gonna be when it's active.
[00:03:31] So what that means is when we're reviewing the current page, I wanna show a slightly different style so we know what page were on. So we'll do that in just a second. And then we wanna that to link to the title. So this is what will be displayed.
[00:03:46] And then whenever this is the active class Gatsby has this really handy helper that will let us just set whenever the current link is the one that's being visited. It'll just set a class name for us. So I'm gonna set that to active. So now we're getting into some theme UI stuff that's a little different.
[00:04:06] We're wanting conditional styles. We want this component to only have a style when we're using a class on it when it has that active class. So to do that, we can use a pretty standard CSS and JS technique. Which is to use the ampersand which references the current element.
[00:04:24] And then we modify it with the active class by adding this .active here. Inside of that we can apply whatever styles we want. So let's say we want our font style to be italic. We'll say that we want the textDecoration to be none because it's the current link we wanna deemphasize,it is a link but not actually deactivated as a link.
[00:04:46] And then I wanna go one step further and I actually wanna tell people that this is the page that they're viewing. So I'm gonna use the after pseudo class and again we just added as a string,and then add a sub Object here. And I'm gonna set the content.
[00:05:02] And this is worth noting the content in CSS and JS ends up looking like it's double quoted because you have to code it once to make it a property for JavaScript. And then you have to quote it for CSS, which means that we've got single quotes for JavaScript.
[00:05:22] And then we've got double quotes for CSS. So I'm gonna set this as the currently viewing. And so these ones are for JavaScript. These ones are for CSS. That's a gotcha. That definitely got me so it's worth just kind of trying to pin that in your head for, when you are trying to use this in the future.
[00:05:44] So now that we've got this, we should be able to just use it. So let's go into our doc's page and I'm just going to toss it in. Let's see how it goes. So let's import TableofContents from table-of-contents and we can drop that right at the bottom. Go to start the site first, yarn workspace theme-dev develop.
[00:06:23] Reload and there we go, we're currently viewing. So, let's add an extra page to make sure that it's working the way we expect. So, we'll go into theme-dev under doc's and I'm gonna create a new file, and we'll call it another.mdx. So, we'll give it a title, let's call it Another Page.
[00:06:46] And we'll say More docs. And there we go. So now we can click around to our pages and see that we've got other pages in there they are showing up the way we expect. The theme is hot reloading, you know we created that file. We didn't have to stop and restart it.
[00:07:04] Just pick the right up. And our Table of Contents is doing what we want it to do. So there is a good place to save our work. So let's get at all, take a look at what we've done. Okay, so we updated the docs page to use our table of contents wrote that table of contents component and created a new Doc's page.
[00:07:28] So we'll commit that. Say, add table of contents. Push that up.
>> So, where are you exporting the page queries do you need that export the static queries as well?
>> No. So the page queries are a special case, where we are signifying to Gatsby that during the build process specifically during on create pages, this template is gonna be used.
[00:07:58] And this query should be treated as a page query. That gives it access to the context which is the, like the variables and stuff. In a static query, a static query is just any use of useStaticQuery inside of a component will be picked up. But again, the limitation here is that we can't use variables there's no access to outside context.
[00:08:21] We can't even interpolate data, I couldn't take a prop and then put that prop in here. So a static query needs to be hardcoded at build time. And the reason for that is that the way that Gatsby's handling the graphQL layer under the hood, that graphQL layer doesn't continue to work once the site is built.
[00:08:40] It's only there during the build. And that means that all of these queries are actually getting compiled away. And that's being done using abstract syntax tree transformations. It's kind of how Babel works under, the hood it takes the code and it breaks it into its component pieces and tokens and then it kind of understands those as a programming language.
[00:09:01] And then the AST gets modified so Gatsby will take the the component. Look for these useStaticQuery instances, break that down into an AST replace it with the results of the query and then rewrite that component with the data in place. So that's why there are restrictions on it because when you get into AST transformations, trying to chase down a variable to where it's declared is really challenging.
[00:09:25] That is something that the team is working on but it is not in place, yet.
>> He wants to know if we can export only one page query from one page file or you can export multiple queries. You can only export one query per page file. But that actually isn't a problem because you can just add, like as many queries as you want next to each other.
[00:09:47] And it would just be data.Doc.Page.data.doc.allfile. So, you can only do one query but that query can have as many subqueries in it as you want.