DEV Community

Jamie Barton
Jamie Barton

Posted on

Create individual category pages

Since we're linking to /categories/:slug from our list of categories inside CategoryList component, we need to create pages for each of them at build time.

This is where we will hook into a special Gatsby API at build time to do this.

Let's first create the template for our category page. Inside the src directory, create a new folder templates.

Here create a file CategoryPage.js and add the following:

import React from 'react';
import { graphql } from 'gatsby';

import ProductList from '../components/ProductList';

export default function CategoryPage({ data: { category } }) {
  const { products } = category;

  return (
    <React.Fragment>
      <h1>{category.name}</h1>

      <ProductList products={products} />
    </React.Fragment>
  );
}
Enter fullscreen mode Exit fullscreen mode

You'll notice we're not exporting a pageQuery, yet. Let's now export a pageQuery, but this time it will look a little different.

Since this is a "template", it should be used when visiting /categories/:slug.

With Gatsby, we must pass some "context" to the template when building it. This context is available to the GraphQL query as variables, so we can use write a query that uses that variable to fetch the page.

In this case we will use the id of each category nodes to fetch from the Gatsby built Chec nodes.

export const pageQuery = graphql`
  query CategoryPageQuery($id: String!) {
    category: checCategory(id: { eq: $id }) {
      id
      name
      products {
        name
        permalink
        ...PriceInfo
      }
    }
  }
`;
Enter fullscreen mode Exit fullscreen mode

As it stands, this file does nothing itself. So let's put it to action!

Inside the root of your project, create the file gatsby-node.js.

We need to hook into the createPages Gatsby API.

Update gatsby-node.js to include the following:

exports.createPages = async ({ graphql, actions }) => {
  const { createPage } = actions;

  const {
    data: { allChecCategory },
  } = await graphql(`
    {
      allChecCategory {
        nodes {
          id
          slug
        }
      }
    }
  `);

  allChecCategory.nodes.forEach(({ id, slug }) =>
    createPage({
      path: `/categories/${slug}`,
      component: require.resolve(`./src/templates/CategoryPage.js`),
      context: {
        id,
      },
    })
  );
};
Enter fullscreen mode Exit fullscreen mode

Inside the createPages function we're running a GraphQL query to get all of our categories, and for each of those, using the createPage action, and providing it the required path, component, and context.

Discussion (2)

Collapse
brandongtripp profile image
Brandon Tripp

Hello, I came across your post trying to build a similar structure on my site. I ma having the issue of the individual pages at the nested route( for instance the individual categories) overriding the base category path. Do you have any suggestions on what might be causing gatsby-node to over ride the page content in the pages directory?

Collapse
notrab profile image
Jamie Barton Author

Hey, I'm not sure I follow 100%. Can you provide me with some more context, or example code?