Search code examples
reactjsdictionarygatsbygatsby-image

How to properly render images using a map function with Gatsby.js


This app was originally built using react, however we have decided to convert everything over and use Gatsbyjs. I am new to Gatsby and I am trying to get my images to render correctly using the artist data. Here is how this part of the data was originally built:

const images = [
  AngelAndJaamiHeadshot,
  BillyHawkinsHeadshot,
  BostonWellsHeadshot,
  BreanahAlvizHeadshot,
  CarloCollantesHeadshot,
  CarloDarangHeadshot,
  ChrisLumbaHeadshot,
  ChrisMartinHeadshot,
  CJDelaVegaHeadshot,
  CyeBongalosHeadshot,
  DanielKimHeadshot,
  DavidDarkieSimmonsHeadshot,
  // DavidDiosoHeadshot,
  DavidSlaneyHeadshot,
  DavinLawsonHeadshot,
  DevinHeadshot,
  DustinYuHeadshot,
  EmilyRowanHeadshot,
  HonrieDualanHeadhot,
  HughAparenteHeadshot,
  JaamiWaaliVillalobosHeadshot,
  JeremyBorjaHeadshot,
  JonathanSisonHeadshot,
  JordanBautistaHeadshot,
  JordanRileyHeadshot,
  JuliaKestnerHeadshot,
  JustinArcegaHeadshot,
  KaitlynSungHeadshot,
  KaylarPrieteHeadshot,
  KeyanaReedHeadshot,
  KikoJamesHeadshot,
  KirstieAndJeremyHeadshot,
  KirstieHeadshot,
  KJEstudilloHeadshot,
  LarkinPoyntonHeadshot,
  MitchVillarealHeadhsot,
  MoanaRakanaceHeadshot,
  NoelleFrancoHeadshot,
  PhuongLeHeadshot,
  SamMooreHeadshot,
  TonyRayHeadshot,
  TracySeilerHeadshot,
  TrishaOcampoHeadshot,
  YutaNakamuraHeadshot,
  defaultHeadshot,
]

export const buildArtistsData = (artists) => {
  return artists.map((artist, idx) => {
    return {
      ...artist,
      imageUrl:
        idx >= 43
          ? defaultHeadshot
          : images[`${artist.firstName}${artist.lastName}Headshot`],
    }
  })
}

And this is how it was used in my Artists component:

const ArtistsPage = () => {
 const artists = buildArtistsData(ARTISTS)

...

<div className={classes.flexContainer}>
          {artists
            .map(
              (
                { city, currentTeam, firstName, lastName, imageUrl },
                idx: number
              ) => {
                return (
                  <div className={classes.flexItem} key={idx}>
                    <img
                      className={classes.artistCardImg}
                      src={imageUrl}
                      alt='artist-image'
                    />
                    <div className={classes.artistCardName}>
                      {`${firstName} ${lastName}`.toUpperCase()}
                    </div>
                    <div className={classes.artistCardText}>{city}</div>
                    <div className={classes.artistCardText}>{currentTeam}</div>
                  </div>
                )
              }
            )}
        </div>

But now that I am using Gatsbyjs and data none of the above will work anymore. Here is what I am working with on the converted Gatsbyjs page:

import React from 'react'
import PropTypes from 'prop-types'
import { StaticImage } from 'gatsby-plugin-image'
import Img from 'gatsby-image'
import { graphql } from 'gatsby'

import { useStyles } from './styles'

const ArtistsPage = ({ data }) => {
  console.log(data)
  const classes = useStyles()
  // const { images } = props

  return (
    <section>
      <article className={classes.artistsContainer}>
        <div className={classes.flexContainer}>
          {data.allArtistsJson.edges.map(({ node }, idx) => {
            return (
              <div className={classes.flexItem} key={idx}>
                <div>
                  {images.map((img, idx) => (
                    <Img
                      key={idx}
                      fluid={img.node.childImageSharp.fluid}
                    />
                  ))}
                </div>
                <div className={classes.artistCardName}>
                  {`${node.firstName} ${node.lastName}`.toUpperCase()}
                </div>
                <div className={classes.artistCardText}>{node.city}</div>
                <div className={classes.artistCardText}>{node.currentTeam}</div>
              </div>
            )
          })}
        </div>
      </article>
    </section>
  )
}
export const pageQuery = graphql`
  query {
    headshots: allFile(filter: { absolutePath: { regex: "/headshots/" } }) {
      edges {
        node {
          childImageSharp {
            fluid(maxWidth: 600) {
              ...GatsbyImageSharpFluid
            }
          }
        }
      }
    }
  }
`

ArtistsPage.propTypes = {
  firstName: PropTypes.string,
  lastName: PropTypes.string,
  currentTeam: PropTypes.string,
  headshots: PropTypes.string,
  dropdown: PropTypes.string,
  data: PropTypes.array,
  images: PropTypes.string,
}

export default ArtistsPage

I was trying to pull image data as props using const { image } = props - but that throws an error so I am really confused as to what and how to map over this to pull my images in for the correct artist.

Also here is my config.js file for reference:

const path = require('path')

module.exports = {
  siteMetadata: {
    title: 'Platform Showcase',
  },
  plugins: [
    'gatsby-plugin-gatsby-cloud',
    'gatsby-plugin-image',
    // {
    //   resolve: "gatsby-plugin-google-analytics",
    //   options: {
    //     trackingId: "",
    //   },
    // },
    'gatsby-plugin-react-helmet',
    'gatsby-plugin-sitemap',
    {
      resolve: 'gatsby-plugin-manifest',
      options: {
        icon: 'src/images/icon.png',
      },
    },
    'gatsby-plugin-mdx',
    'gatsby-plugin-sharp',
    'gatsby-transformer-sharp',
    {
      resolve: 'gatsby-source-filesystem',
      options: {
        name: 'images',
        path: './src/images/',
      },
      __key: 'images',
    },
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `headshots`,
        path: `${__dirname}/src/images/artists/headshots`,
      },
      __key: 'headshots',
    },
    {
      resolve: 'gatsby-source-filesystem',
      options: {
        name: 'pages',
        path: './src/pages/',
      },
      __key: 'pages',
    },
    {
      resolve: 'gatsby-plugin-google-fonts',
      options: {
        fonts: ['material icons', 'roboto:300,400,500,700'],
      },
    },
    `gatsby-theme-material-ui`,
    `gatsby-transformer-json`,
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        path: `./src/data/`,
      },
    },
    {
      resolve: 'gatsby-plugin-root-import',
      options: {
        src: path.join(__dirname, 'src'),
        containers: path.join(__dirname, 'src/containers'),
        images: path.join(__dirname, 'src/images'),
      },
    },
  ],
}

Any help anyone is willing to give would be greatly appreciated.


Solution

  • Your data, when using page queries, is always under props.data so your nesting should look like:

          {data.headshots.edges.map(({ node }, idx) => {
            return (
              <div className={classes.flexItem} key={idx}>
                <Img fluid={node.childImageSharp.fluid} />
              </div>
            )
          })}
    

    Note: I'm assuming that your GraphQL query retrieves properly the data. Test it at localhost:8000/___graphql and tweak your filesystem if needed

    Each image is each node itself (according to query structure) so, since your query is aliasing your allFile as headshots, your data is stored in props.data.headshots.