menu

Gatsby.js

Fast in every way that matters. Gatsby is a free and open source framework based on React that helps developers build blazing fast websites and apps.

Channels
Team

Using Variables in a StaticQuery

December 13, 2018 at 10:05pm

Using Variables in a StaticQuery

December 13, 2018 at 10:05pm

Hey Folks - I'm using gatsby-image in my latest project and I'm finding it a bit cumbersome to have to write a whole query just to display an image. I would love to just have a component that I pass a src to and it does it all under the hood.

So - I'm writing a component with StaticQuery that looks like this:

import React from 'react';
import Img from 'gatsby-image';
import { StaticQuery, graphql } from 'gatsby';
function renderImage({ file }) {
return <Img fluid={file.childImageSharp.fluid} />
}
const MyImg = function (props) {
return <StaticQuery
query={graphql`
query {
file(relativePath: { eq: "wes-and-scott.jpg" }) {
childImageSharp {
fluid(maxWidth: 1000) {
...GatsbyImageSharpFluid
}
}
}
}
`}
render={renderImage}
/>
}
export default MyImg;

Now that works amazingly well, BUT I can't make the filename dynamic.

I read in the docs that Static Query can't take variables - only pages. But I don't want my images to be associated with a page - I want to use this component anywhere I want - like a regular img tag.

I tried string interpolation and that doesn't work.

Any way to get around this? Am I thinking about this in the wrong way?

Show previous messages

December 14, 2018 at 2:44pm

Hey Wes, what I've done, without seeing too much of a performance hit, seems to be exactly what you're suggesting: namely, create a component that queries all image nodes in a specific location and filter the results, finding match and returning it (or a default placeholder, if no match is found).

  • reply
  • like

In order to speed things up, I've broken the images into groups (maybe I have Bio images, Cover images, and Dog images... I'd have <DogImage /> <BioImage /> and <CoverImage />).

  • reply
  • like

And they point to images/dogs, images/bios, images/covers

  • reply
  • like

I'd like to look into the performance implications of this, too. I'm wondering if, since to my understanding the first render and the StaticQuery itself happens on build, and not browser-side, the hit would even be noticeable.

Edited
  • reply
  • like

@wesbos just as a follow up, I set up the following netlify to test this: https://dazzling-bohr-1d9d3d.netlify.com/ using 200 random unsplash images.

  • reply
  • like

The homepage uses 200 components, each with its own StaticQuery and /page-2/ uses a single component with a single StaticQuery, being filtered.

  • reply
  • like

Not sure how much to trust the Chrome profiler, but here's the first page's snapshot

  • reply
  • like
  • reply
  • like

And the second

  • reply
  • like
  • reply
  • like

Thanks for doing that. So from your results, what do they mean?

  • reply
  • like

No problem! I'm not an expert here, but I would say that it means that it means that using a reusable component is worth it! The browser doesn't spend any extra time running the component logic (filtering the 200 images 200 times).

  • reply
  • like

@technocookie first off, thanks for putting in that work. But to be honest, it kind of misses my point - which is reusing the same image component for multiple pages. Where the individual StaticQuerys would only load exactly the image data that is required for that page, while the reusable component in question would load all images even if they're not used on that page.

  • reply
  • like

Exactly. Also, my main concern was more about overfetching than memory usage. So perhaps you could compare the data usage or loading time on a simulated 3G network between the two approaches.

  • reply
  • like

So you are right. Check out https://dazzling-bohr-1d9d3d.netlify.com/page-4/ which uses the reuseable component. If you look at the js being loaded, you will see the metadata and the base64 for the smallest blurry image being loaded for all 200 images.

  • reply
  • like

Compared to https://dazzling-bohr-1d9d3d.netlify.com/page-3 which uses the one-off component

  • reply
  • like

To give this a number: page-3 (one-time component) is 166KB for all requests

  • reply
  • like

and page-4 (reuseable component) is 219KB transferred total

  • reply
  • like

Which is, to be fair, a 30% increase, even though it's "only" 53KB

Edited
  • reply
  • like

That said, if you're using another source like MDX or MD, then you can use the plugins which will extract just the images being used for those pages.

  • reply
  • like

December 15, 2018 at 1:55am

Yeah, the main question with this technique is how many extra images you're loading metadata for. This can get quite large e.g. https://www.gatsbyjs.org/showcase/ used to load preview images in base64 for every showcase site and a while ago (before I disabled it) it was adding ~250kb extra data which caused a noticeable slowdown in time-to-interactive.

  • reply
  • like

As long as you're under say ~200 images, you're probably fine

  • reply
  • like

Explored a possible solution to this https://github.com/gatsbyjs/gatsby/issues/10482

like-fill
4
  • reply
  • like
Show more messages