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.
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
}
}
}
}
}
}
`
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!
Most helpful comment
gatsby-source-contentful
exposes GraphQL fragments so you can use Contentful Images API easily withgatsby-image
. It鈥檚 briefly documented here.Example in your case: