Reusable Gatsby-Image Component with dynamic image sources

后端 未结 3 567
谎友^
谎友^ 2020-12-14 06:51

I’m thinking of using Gatsby-Image for my next project and has been playing around with it a little.

I got it to work on my test project but then I came up with a u

相关标签:
3条回答
  • 2020-12-14 07:46

    I've been searching for this answer as well. Hopefully this answers your question:

    The final code:

    import React from 'react';
    import { StaticQuery, graphql } from 'gatsby';
    import Img from 'gatsby-image';
    
    // Note: You can change "images" to whatever you'd like.
    
    const Image = props => (
      <StaticQuery
        query={graphql`
          query {
            images: allFile {
              edges {
                node {
                  relativePath
                  name
                  childImageSharp {
                    fluid(maxWidth: 600) {
                      ...GatsbyImageSharpFluid
                    }
                  }
                }
              }
            }
          }
        `}
        render={data => {
          const image = data.images.edges.find(n => {
            return n.node.relativePath.includes(props.filename);
          });
          if (!image) {
            return null;
          }
    
          //const imageSizes = image.node.childImageSharp.sizes; sizes={imageSizes}
          return <Img alt={props.alt} fluid={image.node.childImageSharp.fluid} />;
        }}
      />
    );
    
    export default Image;
    

    Using the image:

    import Image from '../components/Image';
    <div style={{ maxWidth: `300px` }}>
        <Image alt="Gatsby in Space" filename="gatsby-astronaut.png" />
    </div>
    

    Explanation

    Because StaticQuery doesn't support string interpolation in its template literal, we can't really pass it any props. Instead we will try and handle check for props in the StaticQuery's Render portion.

    Caveats

    I'm not 100% sure if this affects compiling time since we are scanning all images. If it does, please let me know!

    Update: If you have many images, bundle size can get quite large as this solution does scan ALL images.

    Further customization

    You can adjust the code to show a placeholder image if no props are passed.

    Alternatives

    That said, there is another way you could tackle this but with a bit more work/code.

    Sources

    • I modified the code from this article. (Please note that the article was using deprecated code.)
    0 讨论(0)
  • 2020-12-14 07:46

    Unfortunately from what I can gather the best solution is to write out individual js files for images.

    In @RodrigoLeon's approach, it will cause bundle size to increase DRAMATICALLY. Especially if say you have more than 50 images. Because anytime you use this and loop through all images you create references to them in the component file. So I would not recommend doing it this way.

    0 讨论(0)
  • 2020-12-14 07:48

    The site I am building is an e-commerce platform with thousands of images (for all the products). This presented a major issue with using gatsby which is querying images. For a long time, I had a component that queried all images and matched them up to their respective product. (Like proposed in this ) This is highly inefficient, throwing warnings about the duration of the query.

    An alternate to this is the attach the imageFile to the product on the data level, rather than when trying to render.

    src/gatsby-api/create-resolvers/index.js

    const resolvers = {
        AWSAppSync_Product: {
            imageFile: {
                type: 'File',
                resolve: async (source, args, context, info) => {
                    const node = await context.nodeModel.runQuery({
                        query: {
                            filter: {
                                Key: { eq: source.image1 }
                            }
                        },
                        type: 'S3Object',
                        firstOnly: true
                    });
    
                    if (node && node.imageFile) return node.imageFile;
                }
            },
        },
    }
    
    module.exports = {
        resolvers
    }
    
    

    gatsby-node.js

    exports.createResolvers = async ({ createResolvers }) => {
        createResolvers(resolvers)
    }
    

    src/components/image/index.js

    import React from 'react'
    import Img from 'gatsby-image'
    
    export const Image = props => {
      if (props.imageFile && props.imageFile.childImageSharp && props.imageFile.childImageSharp.fluid) {
        return <Img className={props.imgClassName} alt={props.alt} fluid={props.imageFile.childImageSharp.fluid} />;
      }
    };
    

    Then use it like:

    <Image
      imageFile={product.imageFile}
      alt=""
    />
    

    AWSAppSync_Product is the type of node I am attaching my File to. (which can be found in the graphql playground on localhost). The resolve will match the Key of the S3Object with image1 (which is a string) on the product. This allows me to directly use the product images without having to run a query inside the image component.

    In my opinion, this is a valuable piece of information once you wrap your head around it and it certainly has helped me a lot.

    0 讨论(0)
提交回复
热议问题