TurboTobias
TurboTobias

Reputation: 625

GatsbyJS: component in createPage template

I am using createPages API in Gatsby in order to create pages. I got a template for all of the pages:

const pageTemplate = require.resolve(`./src/templates/page/WpPage.js`)

However, I am not really sure how to use a component in template file. Something like:

import { Herotext } from "./hero/herotext"

const WpPage = ({ data }) => {
  const { wpPage } = data
  return (
    <>
      <Layout>
            <h1><Herotext /></h1>
            <span dangerouslySetInnerHTML={{ __html: wpPage.content }} />
      </Layout>
    </>
  )
}

As seen above I have created herotext.js which should store the title and some other text. My herotext contains:

import React from "react"

export const Herotext = ({ data }) => {
  return <h2>[data.wpPage.ACFundersider.hero.heroHeading}</h2>
}

export const query = graphql`
  query HeroById($id: String) {
    wpPage(id: { eq: $id }) {
      ACFundersider {
        hero {
          heroText
          heroHeading
        }
      }
      id
    }
  }
`

The GraphQL query works when I test in graphiql IDE, but it returns error on frontend:

here was a problem parsing "C:/Users/mig/Desktop/Gatsby/mf20/src/templates/page/hero/herotext.js"; any GraphQL
fragments or queries in this file were not processed.

This may indicate a syntax error in the code, or it may be a file type
that Gatsby does not know how to parse.

File: C:/Users/mig/Desktop/Gatsby/mf20/src/templates/page/hero/herotext.js

./src/templates/page/hero/herotext.js
Module Error (from ./node_modules/eslint-loader/index.js):

C:\Users\mig\Desktop\Gatsby\mf20\src\templates\page\hero\herotext.js
  5:53  error  Parsing error: Unexpected token

Not really sure how to create my herotext.js so it will be used when creating all of the pages with createPage API. I have tried changing my query in all sorts of way but no luck.

When I do console.log(data) in herotext.js I get undefined.

Upvotes: 1

Views: 470

Answers (1)

Ferran Buireu
Ferran Buireu

Reputation: 29320

Gatsby gives you a lot of flexibility to use the template system and the context API. However, the "standard" approach is to use the gatsby-node.js to create dynamic pages, pointing to some template, send some unique value to the template and use it to filter a GraphQL query to fetch the needed data. For example, extracted from Gatsby's tutorial:

  result.data.allMarkdownRemark.edges.forEach(({ node }) => {
    createPage({
      path: node.fields.slug,
      component: path.resolve(`./src/templates/blog-post.js`),
      context: {
        // Data passed to context is available
        // in page queries as GraphQL variables.
        slug: node.fields.slug,
      },
    })
  })

Here you are looping through some array of pages (result.data.allMarkdownRemark.edges.node) to create dynamic pages using the slug as a path value, then, it sends the slug as a unique value to the template (blog-post.js).

In your case, I would suggest a folder structure like /templates/WpPage.js (removing the /page) to avoid potential nesting issues.

Your WpPage, should receive some unique value to filter (it seems to be the id). This is your entry point for your data and from there, you can send it to any desired component:

import React from "react"
import { graphql } from "gatsby"
import Layout from "../components/layout"

export default function SomeTemplate({ data }) {
  conosle.log("your data is in", data);

  return (
      <Layout>
            <Herotext heroText={data.wpPage.ACFundersider.heroText} />
      </Layout>
  )
}

export const query = graphql`
  query HeroById($id: String) {
    wpPage(id: { eq: $id }) {
      ACFundersider {
        hero {
          heroText
          heroHeading
        }
      }
      id
    }
  }
`

Note: I removed the <h1> since you were wrapping an <h2> inside an <h1>.

At this point, your GraphQL query is getting the id (sent via context) and it's being used to filter through wpPage node. In the template query, your data is stored inside props.data (destructured as data in this case). From here, you can send a props called heroText to your HeroText component with the need data and your component will be responsible to print it as you wish:

export const Herotext = ({ heroText }) => {
  return <h2>{heroText}</h2>
}

The main idea to use the template as an entry point of your data. From there, you can distribute and structure the components and data as you wish.

Upvotes: 1

Related Questions