Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Handle URL Parameters with Gatsby

Tags:

reactjs

gatsby

I'm using React & Gatsby to create a website and I've got everything laid out the way I want, I'm just having some problems understanding how to use URL Route parameters to change content that is displayed.

For example, say I have a page categories.js which listens to http://website.com/categories but I want to be able to dynamically handle any URL parameters like such:

http://website.com/categories/animals

When using gatsby-link like so: <Link to="/categories/animals" /> it wants me to create a file called animals.js in a categories folder. Instead, I want categories.js to be able to handle the rendering for this page and select the content appropriate based on the category passed in the URL parameters.

Other than the items displayed, this page is exactly the same through all categories, so it doesn't make sense for every category to have it's own static page.

like image 828
Christian Tucker Avatar asked Dec 18 '22 21:12

Christian Tucker


1 Answers

I think you are wrong when you say:

Other than the items displayed, this page is exactly the same through all categories, so it doesn't make sense for every category to have it's own static page.

In fact, that's exactly where I find GatsbyJS so useful, as it is a static site generator.

It means that you can give Gatsby a template component that will have the same layout for all of your categories, and then Gatsby will fetch data and create static pages for you at build time.

Gatsby is not limited to making pages from files like many static site generators. Gatsby lets you use GraphQL to query your data and map the data to pages—all at build time. (from Gatsby official tutorial)

The idea would be something like this:

in /gatsby-node.js

const path = require(`path`); // you will need it later to point at your template component

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

  // we use a Promise to make sure the data are loaded
  // before attempting to create the pages with them
  return new Promise((resolve, reject) => {
    // fetch your data here, generally with graphQL.
    // for example, let say you use your data from Contentful using its associated source plugin
    graphql(`
      {
        allContentfulCategories {
          edges {
            node {
              id
              name
              description
              # etc...
            }
          }
        }
      }
    `).then(result => {
      // first check if there is no errors
      if (result.errors) {
        // reject Promise if error
        reject(result.errors);
      }

      // if no errors, you can map into the data and create your static pages
      result.data.allContentfulCategories.edges.forEach(({ node }) => {
        // create page according to the fetched data
        createPage({
          path: `/categories/${node.name}`, // your url -> /categories/animals
          component: path.resolve('./src/templates/categories.js'), // your template component
          context: {
            // optional,
            // data here will be passed as props to the component `this.props.pathContext`,
            // as well as to the graphql query as graphql arguments.
            id: node.id,
          },
        });
      });

      resolve();
    });
  });
};

And then you can simply fetch the data on your template component

in /src/templates/categories.js

import React from "react";

export default ({ data: { contentfulCategories: category } }) => {
  return (
    <div>
      <h1>{category.name}</h1>
      <div>{category.description}</div>
    </div>
  );
};

// we can query the needed category according to the id passed in the
// context property of createPage() in gatsby-node.js
export const query = graphql`
  query CategoryQuery($id: String!) {
    contentfulCategories(id: { eq: $id }) {
      name
      description
    }
  }
`;

If you insist in dynamically rendering your categories pages, you can take example of this question that is sort of similar to yours, but note that you will have to manually handle re-rendering if the page's props changes in the componentWillReceiveProps lifecycle method of the React class component.

But I really don't think this is a reliable solution.

like image 196
Nenu Avatar answered Jan 26 '23 20:01

Nenu