在 React 组件中动态导入图像

IT技术 reactjs image import
2021-04-22 14:35:41

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

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} />
    });

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

如何根据从文章组件收到的props (props.imgName) 在文章组件中导入图像?

4个回答

我使用了上下文。

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

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

这段代码没有意义。你从哪里得到assets函数?什么require.contextrequire没有任何context在它
2021-06-12 14:35:41
在这种情况下注入内联图像会导致性能问题。
2021-06-18 14:35:41

您可以从 API 响应动态加载图像,dynamic imports这是目前第 3 阶段的提案

生成的代码应该类似于:

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

查看代码沙盒演示

这个特性在 中是支持开箱即用的create-react-app,如果使用其他系统,可以使用Babel 插件

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

这是我的方式,效果很好:)

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

对于寻找使用 async-await 和自定义react-hooks的现代方法的任何人,我找到了一个非常巧妙的解决方案。创建一个名为的文件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-hooks总是在同一个地方,所以相对路径保持不变。