How do I dynamically import images in React?
Asked Answered
B

4

17

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:

  • I have a folder of MANY images (thousands) - currently it is saved under src/assets/images folder
  • Given a list of images for example as input, I want to render these images dynamically. And not import all because it would be impossible given the insane number of images

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.

Bleb answered 4/6, 2020 at 10:7 Comment(1)
@Daryil Is moving your image folder to public folder an option?Silvey
H
26

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`)} />
Hoebart answered 17/12, 2020 at 19:51 Comment(1)
This is the approach I went with thanksSwift
K
6

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.

Kirsten answered 4/6, 2020 at 10:45 Comment(2)
Thanks for this. Just for the benefit of others who will read this later on too: So this expression does not work <img src={require("../assets/images/${img}.jpg")} /> but this <img src={require("../assets/images/" + img + ".jpg")} /> works?Bleb
@Bleb Yes, as I explained in details - https://mcmap.net/q/743700/-how-to-render-images-from-an-array-using-the-map-method, to make dynamic require work, in simple words, we need to provide an expression which webpack can break / understand in terms of directory (and better if file extensions too). Added TLDR in this answer.Kirsten
B
3

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);
});
Blackfish answered 4/6, 2020 at 10:11 Comment(1)
Thanks mate! Saved my day. Worked on this element for almost 1 hourMatchless
N
2
  // 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.

Numbing answered 2/12, 2020 at 20:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.