msalla
msalla

Reputation: 765

How do you split page templates into individual components, each querying data?

I've created a blog–post template in Gatsby. Now I'd like to break up the page into functional components which each pull in data through useStaticQuery.

Graphql variables only work on page queries as far as I know, and templating literals aren't excepted either:

const Slideshow = props => {

  const data = useStaticQuery(
    graphql`
      query {
        contentfulPost(slug: { eq: "${ props.slug }" }) {
          images {
            title
            description
            sizes
          }
        }
      }
    `

   ...

}

How do I let the component know which data to query?

Upvotes: 0

Views: 59

Answers (1)

Albert Skibinski
Albert Skibinski

Reputation: 499

The component itself should not do any querying. You should abstract that part to a template.

First, use the createPages API in gatsby-node.js to generate the blog posts with a template, something like:

...
createPage({
  path: `${entity.entityTranslation.entityUrl.path}`,
  component: path.resolve(`./src/templates/article.js`),
  context: {
    id: entity.entityTranslation.entityId,
    languageId: lang.toUpperCase(),
  },
})
...

You can see, in my case I pass the ID and language-ID to my template query in article.js:

import React from "react"
import { graphql } from "gatsby"
import Layout from "../components/layout/layout"
import ArticleFull from "../components/node/article-full";

export default ({ data }) => {

  return (
    <Layout>
      <ArticleFull entity={data.drupal.nodeById.entityTranslation} />
    </Layout>
  )
}

export const query = graphql`
  query($id: String!, $languageId: Drupal_LanguageId!) {
    drupal {
      nodeById(id: $id) {
        ... on Drupal_NodeArticle {
          entityTranslation(language: $languageId) {
            ...ArticleFull
          }
        }
      }
    }
  }
`;

The query retrieves the data for each article. In my case, the source was Drupal so this query is very specific for Drupal, but you should be able to customize it to your graphql data. Note how I'm also using a fragment here (ArticleFull).

My actual component is ArticleFull and looks like this:

import React from "react";
import "./article-full.scss"

const ArticleFull = (props) => {

  return (
    <div className="article-full">
      <h1>{props.entity.entityLabel}</h1>
      <div className="article-body" dangerouslySetInnerHTML={{ __html: props.entity.body.processed }}></div>
    </div>
  )
};

export default ArticleFull;

Upvotes: 1

Related Questions