Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GraphQL query works in Gatsby page but not inside class component

There have been a couple of similar questions, but none helped me really understand using a GraphQL inside a (class) component other than the ones in the pages folder.

My project structure looks like that:

-src
--components
---aboutBody
----index.js
--pages
---about.js

I have a page component called about (Prismic single page type) and set up some components to "fill" this page (cleaned up for better readability).

class AboutPage extends Component {

  render() {
    return (
        <LayoutDefault>
          <AboutBody
            introHeadline={this.props.data.prismicAbout.data.intro_headline.text}
            introParagraph={this.props.data.prismicAbout.data.intro_paragraph.text}
          />
        </LayoutDefault>
    )
  }

}

export default AboutPage

This is what my query looks like (had it like this in both files):

export const aboutQuery = graphql`
  query About {
    prismicAbout {
      data {

        # Intro Block
        intro_headline {
          text
        }
        intro_paragraph {
          text
        }
      }
    }
  }
`

(In case I am missing a bracket at the bottom, it's due to cleaning up the query example for SO — as mentioned earlier, it's working in my page component).

My graphql query is at the bottom of the AboutPage page component. It works like a charm and as intended.

But to clean this page up a bit I wanted to create appropriate components and put my query inside each component (e.g. aboutBody, aboutCarousel), again cleaned up a bit:

class AboutBody extends Component {

  render() {

    return (
      <StyledIntro>
        <h3>About</h3>
        <h1>{this.props.data.prismicAbout.data.intro_headline.text}</h1>
      </StyledIntro>
    )
  }

}

export default AboutBody

And I deleted the query from my about page component and put it inside my AboutBody component (exactly the way as shown above).

But with this it always returns the error Cannot read property 'prismicAbout' of undefined (I can't even console log the data, it always returns the same error).

I used import { graphql } from "gatsby" in both files.

Long story short, how can I achieve putting a query inside my class component and render only the component without clarifying the props in my page component like this:

class AboutPage extends Component {

  render() {
    return (
        <LayoutDefault>
          <AboutBody />
        </LayoutDefault>
    )
  }

}

Some blogs posts mention GraphQL Query Fragments, but not sure if this is the correct use case or if it's simply a stupid beginner mistake...

like image 634
Christoph Berger Avatar asked Dec 18 '22 16:12

Christoph Berger


2 Answers

That's because you can't use graphql like this in your component.

To use graphql in a component, you've got two options : useStaticQuery function or StaticQuery component, both from graphql

for useStaticQuery :

import React from "react"
import { useStaticQuery, graphql } from "gatsby"

const MyElement = () => {
  const data = useStaticQuery(graphql`
     query About {
       prismicAbout {
         data {
           intro_headline {
             text
           }
           intro_paragraph {
             text
           }
         }
       }
     }
   `)

   return (
      <StyledIntro>
        <h3>About</h3>
        <h1>{this.props.data.prismicAbout.data.intro_headline.text}</h1>
      </StyledIntro>
   )
}

export default MyElement

with staticQuery

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

const MyElement = () => {
   return(
      <StaticQuery
            query About {
              prismicAbout {
                data {
                   intro_headline {
                       text
                       }
                       intro_paragraph {
                          text
                       }
                   }
                }
             }
         `}
         render={data => (
            <StyledIntro>
               <h3>About</h3>
               <h1>{this.props.data.prismicAbout.data.intro_headline.text}</h1>
            </StyledIntro>
         )}
      />
   )
}

export default MyElement

Hope that helps you!

like image 61
Logan Blangenois Avatar answered Dec 20 '22 06:12

Logan Blangenois


You can only use a query like that in a page component. One option would be to just query it in the page and then pass the data in to your component as a prop. Another is to use a static query in the component.

If your query has variables in it then you can't use a static query. In that case you should either query it all in the page and then pass it in, or you can put the part of the query related to that component in a fragment within that component's file and then use that fragment in the page query.

Example of using fragments in a component and then passing the data into the component:

// MyComponent.js
import React from "react"
import { graphql } from 'gatsby'

const MyComponent = (props) => {

  const { myProp: { someData } }  = props

  return (
    <div>
        my awesome component
    </div>
  )
}

export default MyComponent

export const query = graphql`
  fragment MyAwesomeFragment on Site {
     someData {
         item
     }
  }
`
// MyPage.js
import React from "react"
import { graphql } from "gatsby"

import MyComponent from "../components/MyComponent"

export default ({ data }) => {
  return (
    <div>
      {/*
        You can pass all the data from the fragment
        back to the component that defined it
      */}
      <MyComponent myProp={data.site.someData} />
    </div>
  )
}
export const query = graphql`
  query {
    site {
      ...MyAwesomeFragment
    }
  }
`

Read more about using fragments in Gatsby docs.

like image 35
Caleb Barnes Avatar answered Dec 20 '22 06:12

Caleb Barnes