'Import image dynamically in React component

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

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?



Solution 1:[1]

I used context.

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

I don't know if this is an optimal solution, but it works.

Solution 2:[2]

You can load images dynamically from the API response with dynamic imports that is Stage 3 proposal as of now.

The resulting code should look something like:

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

This feature is supported out of the box in create-react-app, If using other systems, you can use the Babel plugin

Solution 3:[3]

For anyone looking for a modern approach using async-await and custom react hooks, I found a pretty slick solution. Create a file called useImage.js and paste the following code:

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

Then just import the custom hook into your image component, mine looks something like this:

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

The nice thing about this solution is that no matter where your component is in relation to your assets folder, the react hook is always in the same place, so the relative path stays the same.

Solution 4:[4]

there are my way, works nicely:)

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

Solution 5:[5]

I found this worked best for me: I created an index file inside the images folder. there I imported all the images I have and created a class component with the variables assigned to each image import. this is because when we import an image in react using the import statement, that is, import someImage from './somewhere' react assigns the 'someImage' variable to a module with a 'static media' address, my terminology there might be wrong. Here is the example:

import image13_1 from './image13_1.png';
import image13_2 from './image13_2.png';
import image13_3 from './image13_3.png';
import image13_4 from './image13_4.png';
import image13_5 from './image13_5.png';
import image13_6 from './image13_6.png';
import image13_7 from './image13_7.png';

export class IMG{

    1= image13_1

    2 = image13_2

    3 = image13_3

    4 = image13_4

    5 = image13_5

    6 = image13_6

    7 = image13_7

  }
  export default IMG;

from here I just import the IMG class and create an instance of it and call the image number a property:

var img = new IMG()
console.log('img',img[1]

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 STEEL
Solution 2 Agney
Solution 3 Jaden Rose
Solution 4 Abbos Tajimov
Solution 5 Muna Lombe