首页 > 解决方案 > 具有动态图像源的可重用 Gatsby-Image 组件

问题描述

我正在考虑在我的下一个项目中使用 Gatsby-Image,并且一直在尝试使用它。

我让它在我的测试项目上工作,但后来我想出了一个用例,我想像使用常规<img src”image.png”&gt;标签一样使用来自 Gatsby 的。因此,我的问题是如何使 Gatsby 组件可重用?

import React from "react"
import { StaticQuery, graphql } from "gatsby"
import Img from "gatsby-image"
function renderImage({ file }) {
  console.log({ file })
  return <Img fluid={file.childImageSharp.fluid} />
}

// Stateless Image component which i guess will recieve src value as a prop?
// Returns a StaticQuery component with query prop and render prop. Query prop has the graphql query to recieve the images and render prop returns a renderImage function which in return, returns a Img component från Gatsby with set attributes.
const Image = () => (
  <StaticQuery
    query={graphql`
      query {
        file(relativePath: { eq: "gatsby-astronaut.png" }) {
          childImageSharp {
            fluid(maxWidth: 300) {
              ...GatsbyImageSharpFluid
            }
          }
        }
      }
    `}
    // render={data => <Img fluid={data.placeholderImage.childImageSharp.fluid} />}
    render={renderImage}
  />
)
export default Image

我的最佳用例是向我的 Gatsby.config 文件中定义的 relativePath 发出动态请求,然后将每个 Gatsby 中的 src 道具组合起来,并将其与我的资产文件中的所有图像匹配,然后显示它。你们中的任何人都知道这是否可能?

我在文档中读到静态查询不能接受变量——只有页面。但是我不希望我的图像与页面相关联——我想在任何我想要的地方使用这个组件——就像一个常规的 img 标签。

希望我已经说清楚了。请询问您是否有任何问题。

这是一个例子: https ://codesandbox.io/s/py5n24wk27

预先感谢,埃里克

标签: javascriptreactjsgraphqlgatsby

解决方案


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.)

推荐阅读