【问题标题】:Import image dynamically in React component在 React 组件中动态导入图像
【发布时间】:2018-12-14 08:28:00
【问题描述】:

我有一个文章组件,它显示了一个包含所列文章的博客页面。

render() {
    const articles = {
        ...this.state.articles
    }

    const article = Object.keys(articles).map(cur => {
        return <Article
            key={this.state.articles[cur].id}
            imgName={this.state.articles[cur].thumb}
            title={this.state.articles[cur].title}
            meta={this.state.articles[cur].meta}
            clicked={() => this.detailedHandler(this.state.articles[cur].id)}
            detailed={this.state.articles[cur].detailed} />
    });

如您所见,我将带有道具的图像名称传递给文章组件。 然后我想为每篇文章显示适当的图像。

如何根据我从 Articles 组件收到的 props (props.imgName) 在 Article 组件中导入图片?

【问题讨论】:

  • 然后需要将图像名称添加到您在服务器上存储图像的 url 字符串的末尾。然后作为 src 放置到 html &lt;img src=https://myWebsite.com/images/${this.prop.imgName}.jpg /&gt;
  • 我的图片在 src/assets 文件夹中。如果我在 webpack 构建项目后理解正确,这些图像名称和路径将被更改。所以我不能使用这样的相对网址

标签: reactjs image import


【解决方案1】:

我使用了上下文。

const images = require.context('../../../assets/img', true);
loadImage = imageName => (assets(`./${imageName}`).default);
<img src={loadImage("someimage.png")} alt="" />

我不知道这是否是最佳解决方案,但它确实有效。

【讨论】:

  • 在这种情况下注入内联图像会导致性能问题。
  • 这段代码没有意义。你从哪里得到assets 函数? require.context 是什么? require 里面没有context
【解决方案2】:

您可以使用dynamic imports 从 API 响应中动态加载图像,目前为 Stage 3 proposal

生成的代码应该类似于:

loadImage = imageName => {
  import(`./assets/${imageName}.jpg`).then(image => {
    this.setState({
      image
    });
  });
};
render() {
  const { image } = this.state;
  return (
    <Fragment>
      {image && <img src={image} alt="" />}
    </Fragment>
  );
}

View Codesandbox Demo

create-react-app开箱即支持此功能,如果使用其他系统,可以使用Babel plugin

【讨论】:

  • React.lazy 用于导入组件,因此您必须先将图像导入到组件中
  • 现在这将是我认为最正确的答案。这可用于根据环境变量在最终构建中包含图像、服务或模块等资产,这很好,正是我所需要的。你知道是否可以导入给定路径的所有图像,我的意思是,在第一个组件中加载所有图像?谢谢。
  • @sevenlops 在那种情况下我通常会使用import-all.macro
  • 你可能错过了image.default
  • 糟糕... Codesandbox 演示不再存在!
【解决方案3】:

对于任何寻求使用 async-await 和自定义反应钩子的现代方法的人,我找到了一个非常巧妙的解决方案。创建一个名为useImage.js 的文件并粘贴以下代码:

import { useEffect, useState } from 'react'

const useImage = (fileName) => {
    const [loading, setLoading] = useState(true)
    const [error, setError] = useState(null)
    const [image, setImage] = useState(null)

    useEffect(() => {
        const fetchImage = async () => {
            try {
                const response = await import(`../assets/img/${fileName}`) // change relative path to suit your needs
                setImage(response.default)
            } catch (err) {
                setError(err)
            } finally {
                setLoading(false)
            }
        }

        fetchImage()
    }, [fileName])

    return {
        loading,
        error,
        image,
    }
}

export default useImage

然后将自定义钩子导入您的图像组件,我的看起来像这样:

import useImage from '../../hooks/useImage'

import Typography from './Typography' // simple plain-text react component

const Image = ({ fileName, alt, className, ...rest }) => {
    const { loading, error, image } = useImage(fileName)

    if (error) return <Typography>{alt}</Typography>

    return (
        <>
            {loading ? (
                <Typography>loading</Typography>
            ) : (
                <img
                    className={`Image${
                        className
                            ? className.padStart(className.length + 1)
                            : ''
                    }`}
                    src={image}
                    alt={alt}
                    {...rest}
                />
            )}
        </>
    )
}

export default Image

这个解决方案的好处是,无论您的组件相对于资产文件夹在哪里,react hook 总是在同一个地方,所以相对路径保持不变。

【讨论】:

  • 这很好用。我没有使用 Typography 类,所以我只有 if (error) return {alt}; 但是,当文件名错误时,我收到错误“错误:对象作为 React 子项无效(找到:带有键 {alt} 的对象)。如果您打算渲染一组子项,请改用数组。”
  • 我刚刚通过将 useEffect 添加到错误案例中来使文件错误案例工作,如下所示:useEffect(() =&gt; {if (error != null) {return {alt};}}, [alt, error]);
【解决方案4】:

有我的方法,效果很好:)

import React, {useState} from "react"

const getFavorites = (props) => {

  const {item, favouritesNote} = props;
  const [image, setImage] = useState("");

  (function (imageName) {
    import(
      `../../../../assets/images/chart/favorite${imageName ? "_active" : ""}.png`
    ).then((image) => setImage(image.default));
  })(favouritesNote[item.id]);

  return (
    <div>{image && <img alt="" className="img-responsive" src={image} />}</div
  )
}

【讨论】:

  • 很好的答案!我想如果你将变量名从 favouritesNote 更改为 imageSrc 会更清楚。
猜你喜欢
  • 2020-09-23
  • 2018-06-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-02
  • 2023-03-17
  • 2017-10-05
  • 2017-04-19
相关资源
最近更新 更多