Import image dynamically in React component

Dit*_*ito 2 import image reactjs

I have an Articles component that shows a blog page with listed articles.

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} />
    });
Run Code Online (Sandbox Code Playgroud)

As you can see I pass image name with props to Article component. I want then to display the appropriate image for each article.

How do I import an image in Article component based on the props I receive (props.imgName) from Articles component?

小智 20

对于任何寻找使用异步等待和自定义反应挂钩的现代方法的人来说,我找到了一个非常巧妙的解决方案。创建一个名为的文件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
Run Code Online (Sandbox Code Playgroud)

然后只需将自定义挂钩导入到您的图像组件中,我的看起来像这样:

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
Run Code Online (Sandbox Code Playgroud)

这个解决方案的好处是,无论您的组件相对于资产文件夹位于何处,react hook 始终位于同一位置,因此相对路径保持不变。


Agn*_*ney 13

您可以从 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>
  );
}
Run Code Online (Sandbox Code Playgroud)

查看代码沙盒演示

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

  • 哎呀...Codesandbox 演示已经不存在了! (2认同)

Dit*_*ito 5

我使用上下文。

const images = require.context('../../../assets/img', true);
let img = images('./' + props.imageName);
<img src={img} alt="" />
Run Code Online (Sandbox Code Playgroud)

我不知道这是否是最佳解决方案,但是可以。

  • 这段代码没有意义。你从哪里获得“资产”功能?什么是“require.context”?`require` 中没有任何 `context` (3认同)