1

I am just starting with gatsby and having trouble figuring out how to use gatsby-plugin-image in the following case:

const array  = [
    {
        title: "Image 1",
        image: "../images/image1.jpg"
    },
    {
        title: "Image 2",
        image: "../images/image2.jpg"
    },
    {
        title: "Image 3",
        image: "../images/image3.jpg"
    },
    {
        title: "Image 4",
        image: "../images/image4.jpg"
    }
]

export default Section = function(){

    return (
        <div className="bg-white w-full">

                    {array.map((item, index) => (

                        <div key={index} className="flex flex-col items-center lg:items-start">

                               <h2>{item.title}</h2>
                               //How do I use the image plugin here?

                        </div>

                    ))}
        </div>
    )

}

What I tried and doesnt work:

{array.map((item, index) => (

    <div key={index} className="flex flex-col items-center lg:items-start">

           <h2>{item.title}</h2>
           <StaticImage src={item.image}/>

    </div>

))}

I know I am supposed to use GatsbyImage and GraphQl Query for this, but I cant figure out how. What I did now is this workaround:

import image1 from "../images/image1 .jpg"
import image2 from "../images/image2.jpg"
import image3 from "../images/image3.jpg"
import image4 from "../images/image4.jpg"

const array  = [
    {
        title: "Image 1",
        image: image1 
    },
    {
        title: "Image 2",
        image: image2
    },
    {
        title: "Image 3",
        image: image3 
    },
    {
        title: "Image 4",
        image: image4
    }
]

export default Section = function(){

    return (
        <div className="bg-white w-full">

                    {array.map((item, index) => (

                        <div key={index} className="flex flex-col items-center lg:items-start">

                               <h2>{item.title}</h2>
                               <img src={item.image} className="w-50 h-44 object-cover"></img>

                        </div>

                    ))}
        </div>
    )

}

But obviously with this I dont take advantage of gatsby image plugin, and its more tedious.

My Config:

module.exports = {
  plugins: [
    "gatsby-plugin-postcss",
    "gatsby-plugin-image",
    "gatsby-plugin-react-helmet",
    "gatsby-plugin-sharp",
    "gatsby-transformer-sharp",
    {
      resolve: "gatsby-source-filesystem",
      options: {
        name: "images",
        path: `${__dirname}/src/images/`,
      },
      __key: "images",
    },
  ],
};

I found this answer, but this doesnt answer how I would iterate over specific images in my images folder and add additional info (title, description, alttext, etc.). It just shows how I would get 1 specific image as far as I understand.

Any help would be greatly appreciated!

Ferran Buireu
  • 28,630
  • 6
  • 39
  • 67

1 Answers1

4

Given your filesystem structure, I think your best chance is to use GatsbyImage component, as you said. Something like this should work:

{
  allFile(filter: { sourceInstanceName: { eq: "images" } }) {
    edges {
      node {
        childImageSharp {
          relativePath
          gatsbyImageData(layout: FIXED)
        }
      }
    }
  }
}

Keep in mind that page queries are only available in the top-level components (pages), if you want to use it in a custom component (Section) you may need to drill down the props or using a StaticQuery.

When you set up the filesystem, the name attribute becomes the sourceInstanceName so you can create a custom GraphQL query to retrieve all images.

In your component then:

import * as React from 'react'
import { graphql } from 'gatsby'
import { GatsbyImage } from "gatsby-plugin-image"

const HomePage = ({data}) => {
  return (
    <div>
      {data.allFile.edges.node.map((item, index) => {
        return <div key={index}>
          <GatsbyImage image={item.childImageSharp.gatsbyImageData} alt="" />
       </div>

       })}

    </div>
  )
}

export const query = graphql`
  query HomePageQuery {
      allFile(filter: { sourceInstanceName: { eq: "images" } }) {
        edges {
          node {
            childImageSharp {
              gatsbyImageData(layout: FIXED)
            }
          }
        }
     }
  }
`

export default HomePage

Of course, tweak the snippet above to adapt it to your needs.

At this point, you can mix both arrays (array and the GraphQL data) to get the title if needed or you can customize the node to add your custom data.


Given a JSON (or an array) like:

{
  "content": [
    {
      "id": 1,
      "image": "../../path/to/your/image.png"
      "title": "an image"
    },
    {
      "id": 2,
      "image": "../../path/to/your/image.png"
      "title": "an image"
    },
    {
      "id": 3,
      "image": "../../path/to/your/image.png"
      "title": "an image"
    },
  ]
}

Then, taking advantage of the same loop you can so something like:

import * as React from 'react'
import { graphql } from 'gatsby'
import { GatsbyImage } from "gatsby-plugin-image"
import JSONData from "../../content/My-JSON-Content.json"

const HomePage = ({data}) => {
  return (
    <div>
      {data.allFile.edges.node.map((item, index) => {
        if(JSONData.content.path.includes(item.relativePath)) {
          return <div key={index}>
            <h1>{JSONData.content.find(jsonElement=>jsonElement.path ==item.relativePath)}</h1>
            <GatsbyImage image={item.childImageSharp.gatsbyImageData} alt="" />
          </div>
        }
      })}
    </div>
  )
}

Tweak it to adapt it to your needs.

References:

Ferran Buireu
  • 28,630
  • 6
  • 39
  • 67
  • Thanks a lot for your response! It helps alot. You say I can add my custom data to the node. I cant find how to do it, how would I do that? It would be great if I could just attach the necessary data to the file itself, rather then join the data later. – Maximilian Schaum May 30 '21 at 18:01
  • The schema customization is extremely related to your data structure so it's difficult to guess how the code should looks like with sample data. Check https://www.gatsbyjs.com/docs/reference/graphql-data-layer/schema-customization/ – Ferran Buireu May 30 '21 at 18:16
  • The only data I have right now are the images in the images folder. So how could I add for example a title to every image node? Your link tells me I could maybe create a JSON file with every necessary data, but wouldnt I have to join them again aswell? Thanks for your help again btw! – Maximilian Schaum May 30 '21 at 19:10
  • Found this, which perfectly answers my question, it seems to have a downside of getting slow with many images, but I dont have that many, so its fine for now. https://stackoverflow.com/a/56508865/16038414 Thank you for your help you sent me in the right direction :) – Maximilian Schaum May 30 '21 at 21:52
  • I don't think it fits you since in the end, is using the same node as mine (`allFile`) you can't add the `title` directly. The easiest solution given your use-case is to create a JSON or a markdown with the images paths and the titles. Then, using a query (depending on the chosen node it will be different) you can fetch that data using GraphQL and loop the object like I'm doing in with the `allFile`. If you found the article you can answer your own question or accept/upvote mine to close the issue. I was about to provide more details but it seems you have already managed to fixed it – Ferran Buireu May 31 '21 at 05:05
  • 1
    I agree I went with the JSON method you proposed and it worked better. Didnt have to copy my array from file to file when reusing the images. I cant upvote yet, so I accepted your answer. Thanks again, you helped me alot! – Maximilian Schaum May 31 '21 at 14:10