Search code examples
javascriptnode.jsreactjsgatsbyslug

Gatsby category slugs not working from dynamic category page


In my gatsby-node.js I create dynamic Category pages:

exports.createPages = async ({ graphql, actions: { createPage } }) => {
  const {
    data: { projects, categories },
  } = await graphql(`
    query Projects {
      projects: allGraphCmsProject(filter: { stage: { eq: PUBLISHED } }) {
        nodes {
          id
          slug
        }
      }
      categories: allGraphCmsCategory {
        nodes {
          id
          slug
        }
      }
    }
  `);

  projects.nodes.forEach(({ id, slug }) => {
    createPage({
      path: `${slug}`,
      component: path.resolve('./src/templates/ProjectPage.tsx'),
      context: { id, slug },
    });
  });

  categories.nodes.forEach(({ id, slug }) => {
    createPage({
      path: `/category/${slug}`,
      component: path.resolve('./src/templates/CategoryPage.tsx'),
      context: { id },
    });
  });
};

Inside src/templates/CategoryPage.tsx I render a CategoryList.tsx component.

In the browser on the page /category (src/pages/category.tsx), I render also the list categories (CategoryList.tsx component). When I click a category from this page it's working fine and it shows a url like /category/category-one and shows the categorie page in the browser.

But then if I click another category (from within a category page (src/templates/CategoryPage.tsx), I get an url like /category/category-one/category-two?


Solution

  • But then if I click another category (from within a category page (src/templates/CategoryPage.tsx), I get an url like /category/category-one/category-two?

    Your page generation looks good, except some unnecessary template literals:

      projects.nodes.forEach(({ id, slug }) => {
        createPage({
          path: slug, // before was path: `${slug}`,
          component: path.resolve('./src/templates/ProjectPage.tsx'),
          context: { id, slug },
        });
      });
    

    Your issue appears because you are missing an initial slash (/) at the beginning of the to props of the <Link> component.

    On your category page:

    <Link to={`/${slug}`}/>{categoryName}</Link>
    

    Note: I don't know your page structure but the goal is to add an initial slash.

    This is because slug, may come or not with an initial slash. If it doesn't, it will concatenate the current URL to the slug itself, like an anchor (<a>) normally does.