iterating over data including image in Gatsby

Viewed 967

In Gatsby I would like to iterate over an array, which contains objects. One of the properties of each object would be an image. I would like to be able to use Gatsby Image.

Here is one example of when I'd like to do so: a page on a website with a gallery of images, each image opens a particular associated video when clicked. Perhaps I'd like 20, 50, or even 100+ objects in the array:

const videos = [
  {
    id: 1,
    name: 'Festival 2018',
    url: 'https://www.youtube.com',
    img: // HOW TO ACHIEVE?
  },
  // Many more objects
]
videos.map((item) => {
  return (
    <Img
      key={item.id}
      fluid= // HOW TO ACHIEVE?
      alt={item.name}
      onClick={() => openPlayer(item.url)}
    />
  )
})

I understand how to query for single images with GraphQL; or how to query multiple images and use aliases; or how to query all images from a folder. But I have't worked out how to achieve my goal. There's probably a better way. Thanks in advance.

1 Answers

To use internal images in gatsby-image you need to allow Gatsby and their transformers and sharps to know where the images are located using the gatsby-source-filesystem. This will create queryable nodes from your images and will allow you to use gatsby-image with them.

Applied to your case, you need to put all images in the same folder, let's say /src/images and:

const path = require(`path`)

module.exports = {
  plugins: [
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `images`,
        path: path.join(__dirname, `src`, `images`),
      },
    },
    `gatsby-plugin-sharp`,
    `gatsby-transformer-sharp`,
  ],
}

There, your JSON object will look like:

const videos = [
  {
    id: 1,
    name: 'Festival 2018',
    url: 'https://www.youtube.com',
    img: '/relative/path/to/your/image.extension',
    extension: 'png'
  },
  // Many more objects
]

Note: thanks John for the clarification about the extension field. Source: https://stackoverflow.com/a/56012718/13714522

In your case, since you are using a JSON-based source, you will need to add the gatsby-transformer-plugin. The configuration will look like:

module.exports = {
  plugins: [
    `gatsby-transformer-json`,
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        path: `./src/data/`,
      },
    },
  ],
}

Note: assuming that the JSON is placed in /src/data

Also assuming that your JSON file is named data.json, if everything is properly set, Gatsby will create a GraphQL node called allDataJson. Then you only last to create a query (page query or static query) with the following content:

{
  allDataJson {
    edges {
      node {
        name
        url
        id
        img {
          childImageSharp {
            fluid(maxWidth: 1000, quality: 100) {
              ...GatsbyImageSharpFluid
            }
          }
        }
      }
    }
  }
}

Note: check your exact query in the localhost:8000/___graphql playground

If your paths are correct, Gatsby will create the childImageSharp node which will allow you to use your own internal images within gatsby-image feature. Since your queried data is stored inside props.data, your final loop should look like:

props.data.allDataJson.edges.node.map((item) => {
  return (
    <Img
      key={item.id}
      fluid={item.img.childImageSharp.fluid}
      alt={item.name}
      onClick={() => openPlayer(item.url)}
    />
  )
})
Related