Gatsby Would Seem to Require an 10x the Effort of Any Other Framework to Add One Image: What Am I Not Understanding?

Viewed 709

This is the code for a single image in any other Javascript framework in existence:

<img src="images/someFile.png" />

... possibly with some styling.

This is the code for a single image in Gatsby (basically copied from the Gatsby Image documentation page, https://www.gatsbyjs.org/docs/gatsby-image/ ... and this is just a simple example):

import { useStaticQuery, graphql } from "gatsby"
import Img from "gatsby-image"
export default function Image() {
  const data = useStaticQuery(graphql`
    query {
      file(relativePath: { eq: "images/someFile.png" }) {
        childImageSharp {
          fixed {
            ...GatsbyImageSharpFixed
          }
        }
      }
    }
  `)
  return (
      <Img fixed={data.file.childImageSharp.fixed} />
  )
}

Holy hell, I'm supposed to write all that code (ok, I don't have to repeat the imports, but still) for every image in my site?!?

That can't be right, so clearly I'm not understanding something. Can someone please clarify what I'm not getting about Gatsby?

If it truly takes that much code to just to add one image to a site, Gatsby must be the slowest framework ever to develop in (but from it's popularity I can't believe that's true). Or do most Gatsby sites just use very few images?

3 Answers

At the very start of the page which you mention there is a bit of explanation

gatsby-image is a React component designed to work seamlessly with Gatsby’s native image processing capabilities powered by GraphQL and gatsby-plugin-sharp to easily and completely optimize image loading for your sites.

gatsby-plugin-sharp can compress jpeg/png images

Holy hell, I'm supposed to write all that code (ok, I don't have to repeat the imports, but still) for every image in my site?!?

I think you can extract some things as params like eq: "images/someFile.png" and make it reusable

Example

import { useStaticQuery, graphql } from "gatsby"
import Img from "gatsby-image"
export default function Image({source}) {
  const { file: {childImageSharp: {fixed} } } = graphql(`
    query($source: String!) {
      file(relativePath: { eq: $source }) {
        childImageSharp {
          fixed {
            ...GatsbyImageSharpFixed
          }
        }
      }
    }
  `, {source})
  return <Img fixed={fixed} />
}

It's a nice topic to discuss and share. It's always up to you to use a <img> tag (importing assets directly in the component) or <Img> React's Component from Gatsby, adding and extending all support it has. From Gatsby Image documentation:

gatsby-image is a React component specially designed to work seamlessly with Gatsby’s GraphQL queries. It combines Gatsby’s native image processing capabilities with advanced image loading techniques to easily and completely optimize image loading for your sites. gatsby-image uses gatsby-plugin-sharp to power its image transformations.

Note: gatsby-image is not a drop-in replacement for <img />. It’s optimized for fixed width/height images and images that stretch the full-width of a container. Some ways you can use <img /> won’t work with gatsby-image.

So, without going into detail of all the benefits of using <Img> from Gatsby (compression, lazy loading, fluid sizes, etc), it's not that hard to implement for every single image if you take into account a few details.

Gatsby is a CMS/data-sourced based framework so, by default, all data comes from a CMS or somewhere outsourced, meaning that it has to be queried via GraphQL. In those queries, ideally, you'll prepare your data, images included. That will avoid you to use the staticQuery you showed. For example, retrieving all images once you've set up your filesystem should look like:

{
  allImageSharp {
    edges {
      node {
        fluid(maxWidth: 800) {
          ...GatsbyImageSharpFluid
        }
      }
    }
  }
}

Note: this is an example query, the idea is to fetch and gather all data needed from an image to pass it to <Img> component

Then, in your component you simply need to:

//...other imports
import Img from "gatsby-image"

const yourComponent= ({ data }) => {

  return <Layout>
    {data.edges.map(({ node })=> <Img fluid={node.childImageSharp.fluid} />)}
  </Layout>;
};

Gatsby's example from using <Img> maybe it's not the most accurate use-case to do it because it involves a staticQuery, another way of importing data that is not as usual as it seems. You can easily avoid it by using a standard GraphQL query, saving you a lot of lines of code.

What I'm trying to say is that if you set your data properly, using Gatsby's image it's almost like using the common HTML <img> tag.

The sample code you showed (from Gatsby's documentation) will always show the astronaut image, but of course, it's completely up to you to use a single <Img> component and remove the <Image> one or re-use it as you wish.

See Importing Assets Directly Into Files and Using the Static Folder

import React from "react"
import importedImage from "../images/gatsby-icon.png"

const IndexPage = () => (
  <>
    <img src={importedImage} alt="Description of my imported image" />
    <img
      src="staticfolderimage.jpeg"
      alt="Description of my image in the ./static folder"
    />
  </>
)

export default IndexPage
Related