JavaScript
min read
May 12, 2020
April 30, 2020

Querying Static vs Dynamic Data in Gatsby

Querying Static vs Dynamic Data in Gatsby
Table of contents

Gatsby uses different kinds of plugins to pull data from different data sources into Gatsby. Once it gets the desired data, it uses GraphQL to query that data. Now, why does it use GraphQL is a topic for another day. Today we will focus on what are the different ways of querying data, and what kind of data needs to be queried where.

When I started learning Gatsby I had an impression that we can only build static sites with Gatsby, like a blog site where you just pull all the data from a source, bundle it together, deploy and let the browser handle the rest. But that is not it! Once the Gatsby site hits the browser we can rehydrate it into a React app and utilize all the benefits of a React App. Which means we can say that it is not just a static site generator but a progressive app generator. Where you can leverage all the static functionality and still be able to query the dynamic data.

Essentially there are two parts to any web app

  1. Static
  2. Dynamic

Static Data

Static data is the data/content that does not change as per user interaction. Think of a product detail page. You don’t change product images or product attributes every few minutes, right? This would be considered as static Data and we can query this type of data with two types of queries in Gatsby.

  1. Page Query
  2. Static Query

Depending on the use case, if we want to query data for specific pages we generally opt for Page Query whereas Static Query is used to querying data inside a component.

The main difference between the two is that Page Query accepts query variables during build time. While that is not possible for Static Queries.

1. Page Query

Generally, we use Page Queries to dynamically generate templates/pages. For example, think of the product detail pages on a website, a thousand products mean a thousand pages. We can do this by using createPages hook in our gatsby-node.js file. All we need is a path and a unique identifier for each Product.


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

  const allProducts = await graphql(`
      {
        allCommerceProduct {
          nodes {
            drupal_id
            path{
              alias
            }
          }
        }
      }
    `);

  
  allProducts.data.allCommerceProduct.nodes.map(async (node) => {
    createPage({
      path: node.path.alias,
      component: path.join(__dirname, '/src/templates/ProductDetail.js'),
      context: {
        id: node.drupal_id,
      },
    });
  });
};

Take a look at the above code. All we are doing is fetching a unique ID related to each product and it’s path alias for each product a from data source which in our case is Drupal. Then we are passing this data to our template file as a context value.

We can access this value at /src/templates/ProductDetail.js. Now in our ProductDetail template, we can use the unique ID to query data for each product. Take a look at the code below.


import React from 'react';
import { graphql } from 'gatsby';
import Layout from '../components/Layout';


export default (props) => {
  const { nodes } = props.data.allCommerceProduct;

  return (
    <Layout>
        {nodes[0].title}
    </Layout>
  );
};

export const productQuery = graphql`
query($id: String!) {
  allCommerceProduct (filter: {drupal_id: {eq: $id}}) {
    nodes {
      title
  }
}
`;

Gatsby uses the variable value at build time to generate the Product details for each product. To learn more about page queries visit this link.

2. Static Query

Static Query is quite simple. We can also call it as a Dumb query more like dumb components in React which are not dependent on an external value to fetch the data. We can use them anywhere, including in the pages. Here is an example of a static query.


import { graphql, StaticQuery} from 'gatsby';
import React from "react"


const Product = (props) => {
  const data = props.allCommerceProduct;

  return(
    <div>
      {data.nodes[0].title}
    </div>
  );
}
export default props =>  (
    <StaticQuery
        query={graphql`
      query ProductQuery {
        allCommerceProduct {
           nodes {
            title
          }
        }
      }
    `}
        render={(data) => (
            <Product {...data} />
        )}
    />
)

To learn more about Static Queries. Follow this link.

Dynamic Data

Think about a cart in an e-commerce decoupled site. The cart data keeps changing every time the user adds something to their cart, which means the user is going to interact with your site backend every time they add something to their cart. Which implies that this piece of data cannot be static. So in other terms, we can identify the dynamic part of our app as the data that keeps changing during runtime.

Here one can draw an equivalent of this particular use case of our cart to that of a classic server-side rendered app. And how do we solve this problem? I addressed at the beginning that we can rehydrate a Gatsby app into a React app and utilize all the benefits of a React app. So we can fetch data during runtime in Gatsby, as we would generally do in a React app which is through API calls like a Rest API, GraphQL API, or anything else.

For an example here is a runtime GraphQL query which uses an apollo-client. We also call it a GQL query.


import React, {useState, useEffect} from 'react';
import gql from 'graphql-tag';
import { useQuery } from '@apollo/react-hooks';

const ProductList = {
   const queryParams = {
    category: "clothing"
  };
   const { loading, data } = useQuery(GET_ALL_PRODUCTS, {
    variables: queryParams,
  });
  // Use the data as you want. 
  return (
    <></>
  )
}
const GET_ALL_PRODUCTS = gql`
  query($productTypeId: $category: [String]) {
    products: allCommerceProduct {

  }
}

Nothing fancy happening here. Just passing query parameters to the GQL during runtime and it fetches the data accordingly. If you are in a Class component you can do this in the ComponentDidMount lifecycle method and in a functional component, we can use useEffect to render our data as per the state change.

That is it. Hope you got what you were looking for.

P.S - If you have any queries kindly mention them in the comments section. Happy to answer!

Written by
Editor
No art workers.