Daryll
Daryll

Reputation: 571

How do I dynamically import images in React?

Have seen a couple of answers online but there are no clear explanations and the solutions don't work. So this is what I am trying to do:

This is my current way of implementing it (which does not work):

// for example
const imageList = ['img1', 'img2', 'img3' /*...so on */]

const getImagePath = (image) => {
  return `../assets/images/${image}.jpg`
}

function ImagesPage() {
  return (
    <>
      <p>Below should show a list of images</p>
      {imageList.map((img) => {
        return <img src={require(getImagePath(img))} />
      })}
    </>
  )
}

From what I read online, this has something to do with the way webpack works, and this will only work if the exact string path is input into the require:

// This works:
<img src={require('../assets/images/img1.jpg')} />

// But all these will not work:
<img src={require(getImagePath(img))} />

const img = 'img1.jpg'
<img src={require(`../assets/images/${img}`)} />

Any idea how I can get this dynamic importing of images to work in the scenario I described above? I think this post will be quite helpful to the others searching for an answer too.

Upvotes: 17

Views: 17120

Answers (4)

mleister
mleister

Reputation: 2585

Adding .default will do the trick

<img src={require(`../../folder-path/${dynamic-filename}.png`).default} />

Update November 2022

After upgrading to Webpack 5 you will no longer need to append .default. In fact, quite the opposite. If you keep it, no image is displayed because no src attibut is added to the image.

<img src={require(`../../folder-path/${dynamic-filename}.png`)} />

Upvotes: 27

root
root

Reputation: 183

  // for example
const imageList = ['img1', 'img2', 'img3' /*...so on */]

const getImagePath = (image) => {
  return `../assets/images/${image}.jpg`
}

function ImagesPage() {
  return (
    <>
      <p>Below should show a list of images</p>
      {imageList.map((img) => {
        return <img src={require(getImagePath(img)).default} />
      })}
    </>
  )
}

If you are using "create react app", adding .default after require works fine, it sets all images dynamically from local image folder.

Upvotes: 2

Ajeet Shah
Ajeet Shah

Reputation: 19863

TLDR;

// All of these works

const fileNameExt = 'foo.jpg'
<img src={require('../images/' + fileNameExt)} />
<img src={require(`../images/${fileNameExt}`)} />

const fileName = 'foo'
<img src={require('../images/' + fileName + '.jpg')} />
<img src={require(`../images/${fileName}.jpg`)} />

// These does not work:

const myPathVariable1 = '../images/' + 'foo' + '.jpg'
<img src={require(myPathVariable1)} />

const myPathVariable2 = '../images/' + 'foo.jpg'
<img src={require(myPathVariable2)} />

You can require dynamically with expression.

File names:

const imageList = ["img1", "img2", "img3", ... ]

And to render at UI (add directory path and the extension inside require):

{
  imageList.map(img => {
    return <img src={require("../assets/images/" + img + ".jpg")} />
  })
}

Why it works?:

Webpack can understand this expression, by generating context about directory and extension, and can load all the matching modules.

Upvotes: 6

Paul Fitzgerald
Paul Fitzgerald

Reputation: 12129

Update your getImagePath function to return an img element.

const getImage = (image) => {
   return <img src={require(`../assets/images/${image}.jpg`)} />
}

Then your map function would look like this:

imageList.map((img) => {
   return getImage(img);
});

Upvotes: 3

Related Questions