Gatsby: Pulling Contentful data down and using gatsby-image for optimatization

Created on 30 May 2018  路  5Comments  路  Source: gatsbyjs/gatsby

Summary

I've been looking at some ways to optimize the site I am building and came across the plugin gatsby-image

It looks handy however, I'm little stumped as to how to implement it. I have two components that I want to use gatsby-image on: Upcoming event list, and Event Detail template.

The event detail template is pulling data down from Contentful to populate the detail page. This is where I am getting stumped. The way I understand graphql requires you to be specific in your query. How can I both do a query for my contentful data and do the image optimization? This is the same case for the upcoming events, except the query is done on the layout.

Relevant information

EventDetail.js

import React, { Component } from 'react'
import Link from 'gatsby-link'
import Img from 'gatsby-image'

export default class EventDetail extends Component {
  render() {
    const data = this.props.data.contentfulShow;
    const convertDate = new Date(data.date)

    return (
      <div className="content-box">
        <div className="event-detail" >
          {data.image ? <img className="event-detail-image" src={data.image.file.url} alt=""/> : null }
          <div className="event-detail__content">
            <h2 className="event-detail-name">{data.name.toUpperCase()}</h2>
            <h3 className="event-detail-date">{`${convertDate.toLocaleDateString({ weekday: 'short', month:'short', day:'numeric'}).toUpperCase()} ${convertDate.toLocaleTimeString([], {hour: '2-digit', minute: '2-digit'})}`}</h3>
            <h3 className="event-detail-coverprice" >{!data.coverPrice ? `No Cover` : `$${data.coverPrice.toFixed(2)}`}</h3>
            <div dangerouslySetInnerHTML={{__html: data.description.childMarkdownRemark.html}} />
            <Link to='/'>Back to Upcoming Events</Link>
          </div>
        </div>
      </div>
    )
  }
}

export const eventDetailQuery = graphql`
  query eventDetailQuery($slug: String!) {
      contentfulShow (slug: {eq: $slug}) {
        slug
        name
        date
        coverPrice
        description {
          id
          childMarkdownRemark {
            id
            html
          }
        }
        image {
          file {
            url
          }
        }
    }
  }

`

UpcomingEvents.js

import React, { Component, PropTypes } from 'react';
import Link from 'gatsby-link'
import Pagination from './Pagination'
import Event from './Event'

export default class UpcomingEvents extends Component { // eslint-disable-line react/prefer-stateless-function
  render() {
    const { group, index, first, last, pageCount, additionalContext } = this.props.pathContext;
    const showCount = additionalContext.showCount;
    const paginateControls = { index, first, last, showCount, pageCount};

    const events = group.map((node) => {
      const show = node.node;
      return <Event key={show.id} 
                    showName={show.name} 
                    showDate={show.date} 
                    coverPrice={show.coverPrice}
                    image={show.image ? show.image.file.url : null}
                    slug={show.slug} />
    });

    return (
      <div className="content-box">
        <h3 className="content-box__header-tab">UPCOMING EVENTS</h3>
        <div className="c-eventsList">
          <Pagination paginateControls={paginateControls}/>
          { events }
          <Pagination paginateControls={paginateControls}/>
        </div>
      </div>
    );
  }
}

Layout.js

import React from 'react'
import PropTypes from 'prop-types'
import Link from 'gatsby-link'
import Helmet from 'react-helmet'

import lobsterFont from "typeface-lobster"

import Navigation from '../components/Navigation'
import SocialMedia from '../components/SocialMedia'
import NextEvent from '../components/NextEvent'
import AddressBlock from '../templates/AddressBlock'
import Footer from '../components/Footer'

import 'bootstrap/dist/css/bootstrap.css';
import '../styles/styles.min.css';


const Header = () => (
  <div
    className="header"
  >
    <div
      style={{
        margin: '0 auto',
        maxWidth: 960,
        padding: '1.45rem 1.0875rem',
      }}
    >
      <h1 className="header__logo">
        <Link
          to="/"
          style={{
            color: 'white',
            textDecoration: 'none',
          }}
        >
          Tootle's
        </Link>
      </h1>
    </div>
  <Navigation />
  </div>
)

const TemplateWrapper = ({data, children}) => {
  const nextShow = data.allContentfulShow.edges[0];
  return (
    <div>
      <div className="c-background-image"></div>
      <div className="c-background-overlay"></div>
      <div className="wrapper">
        <Header />
        <div className="c-layout">
          <Helmet
            title="Tootle's Pumpkin Inn"
            meta={[
              { name: 'description', content: 'Sample' },
              { name: 'keywords', content: 'sample, something' },
            ]}
            >
            <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css"/>
            <link rel="stylesheet" href="style.css"/>
          </Helmet>

          <div className="c-layout__content">
            <div className="c-layout__main">
              {children()}
            </div>
            <div className="c-layout__aside">
              <SocialMedia />
              <NextEvent nextShow={nextShow}/>
              <AddressBlock/>
            </div>
          </div>
          <Footer/>
        </div>
      </div>
    </div>
  )
}

TemplateWrapper.propTypes = {
  children: PropTypes.func,
}

export default TemplateWrapper


export const nextEventQuery = graphql`
  query nextEventQuery {
    allContentfulShow (
      limit: 1
      sort: { fields: [date], order:DESC }
    ) {
      edges {
        node {
          name
          date
          slug
          coverPrice
          image {
          file {
            url
          }
          }
        }
      }
    }
  }
`



question or discussion

Most helpful comment

gatsby-source-contentful exposes GraphQL fragments so you can use Contentful Images API easily with gatsby-image. It鈥檚 briefly documented here.

Example in your case:

export const nextEventQuery = graphql`
  query nextEventQuery {
    allContentfulShow (
      limit: 1
      sort: { fields: [date], order:DESC }
    ) {
      edges {
        node {
          name
          date
          slug
          coverPrice
          image {
            sizes(maxWidth: 1280) {
              ...GatsbyContentfulSizes
            }
          }
        }
      }
    }
  }
`
const sizes = data.allContentfulShow.edges[0].node.image.sizes
<Img sizes={sizes} />

All 5 comments

gatsby-source-contentful exposes GraphQL fragments so you can use Contentful Images API easily with gatsby-image. It鈥檚 briefly documented here.

Example in your case:

export const nextEventQuery = graphql`
  query nextEventQuery {
    allContentfulShow (
      limit: 1
      sort: { fields: [date], order:DESC }
    ) {
      edges {
        node {
          name
          date
          slug
          coverPrice
          image {
            sizes(maxWidth: 1280) {
              ...GatsbyContentfulSizes
            }
          }
        }
      }
    }
  }
`
const sizes = data.allContentfulShow.edges[0].node.image.sizes
<Img sizes={sizes} />

@ryanditjia I kinda get it now. I tried setting up a query similar to what you have on gatsby-node to pull in my paginated shows however, I get an error stating the fragment doesn't exist:

GraphQLError: Unknown fragment "GatsbyContentfulResolutions"

I apologize if the fix for this is known. I'm not very familiar with graphql

Try moving the query into the page component.

If you鈥檙e getting the error inside GraphiQL, that鈥檚 because the fragment doesn鈥檛 work with it.

Feel free to ask if you still have more questions with GraphQL, it鈥檚 a lot of fun once you get the hang of it.

Due to the high volume of issues, we're closing out older ones without recent activity. Please open a new issue if you need help!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

3CordGuy picture 3CordGuy  路  3Comments

andykais picture andykais  路  3Comments

signalwerk picture signalwerk  路  3Comments

timbrandin picture timbrandin  路  3Comments

ghost picture ghost  路  3Comments