Search code examples
reactjsgatsbygatsby-image

How can I use gatsby-plugin-image in a map function?


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!


Solution

  • 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: