How to do Dynamic images in ReactJS?

J. Doe picture J. Doe · Jan 22, 2019 · Viewed 7.5k times · Source

In my system I have a few images that a user can have presented and it's extremely advantageous to me to be able to just pass in an id and then have that image be presented to the user.

(One use case: Articles in the system have images associated with them, there are many articles in the system, it'd be ideal to pull out just the image-id and have the image dynamically displayed based upon that id. There is no realistic possible way I can statically give an image path for each article.)

Unfortunately I've tried to figure this out and haven't gotten far at all. I'd be super-duper appreciative of a "Explain it to me like I am 5" answer on this one.

I have been trying to use images in two different ways and both have unfortunately not worked at all for me. Where unfortunately I am going to need both to continue :(

1: Putting it as a background of a div. [I am using it as a carousel with overlaying text here.]

2: Putting it as just a standalone image. [This is going to make up the 95%+ case of image use through the webapp.]

I'd love to in a perfect world just pass in an object like this to props.

  articleDetails = {
        articleId: 38387,
        articleTitle: "Magical Unicorn Article"
        articleContent: "I am not that creative, but here is some content."
    }


       <IndividualArticle article={articleDetails}/>

Then for props to take this in and convert it into the image path to my local files.

   templateStringForImage = `../../../../articleImages/${this.props.article.articleId}.png`

Then for this template string to be used as:

1: the background image of a div

    <div
         className="container"
         style={{
             backgroundImage: `url(${templateStringForImage})`         ,                       
             height: "576px"          
    }} 
enter code here

 </div>

2: standalone image

      <Image
            src={require({templateStringForImage})}
      />

Some of the things I've tried:

I've tried a few changes like changing the code around to be like:

     var Background = `../../../images/articleImages/${         
              this.props.article.image     
     }`; 

     <div style={{                
             backgroundImage: url('../../../images/articleImages/article3Image.png'),                                
              height: "576px"          
     }} 

But unfortunately that only gave me these errors.

 Line 32:  'url' is not defined  no-undef

Also when I went to try and use the new Background object like this I got a different error

             var Background = `../../../images/articleImages/${         
                   this.props.article.image     
            }`; 

          <Image
               src={require({Background})}
          />

The error was:

         Error: Cannot find module '[object Object]'

My current system/errors:

-I have a bunch of images like article1Image.png, article2Image.png, article3Image.png specified in the src code in an image folder.

-I want to pass "article1Image.png" into the object directly and have an image produced.

-I tried to do something like this and it has consistently failed, I don't even get an error message when I attempt to use it as a backgroundImage on a div unfortunately... it's literally just blank space on my screen. No broken image icon, just a void.

   var Background = `'../../../images/articleImages/${
         this.props.article.image
    }'`;

    <div
    style={{
      backgroundImage: `url(${Background})`,
      height: "576px"
    }}

-When attempting to use semantic-ui's Image I am also running into a nasty error

      <Image
        src={require(Background)}
      />

Error:

 Error: Cannot find module ''../../../images/articleImages/article2Image.png''

Yet shockingly enough THIS works, when I give it as a static string like this.

      <Image
        src={require('../../../images/articleImages/article2Image.png')}
      />

But even when I give the string path directly into the backgroundImage of the div it still appears empty...

      <div
           style={{
               backgroundImage: `url(../../../images/articleImages/article3Image.png)`,
               height: "576px"
         }}

Thanks all I truly appreciate the help lots and lots!

Answer

Matty J picture Matty J · Jan 22, 2019

There are 2 different solutions based on what you have tried.

URL

If you want to access them via style={{ backgroundImage: 'url(...)' }}, the url will need to be accessible from the front-end. If you used create-react-app, that would mean placing images in the public folder instead of the src folder.

So if you had images in the public folder like: /public/articleImages/article2Image.png, you could use the url style attribute:

const imageName = 'article2Image.png';
<div style={{ backgroundImage: `url('/articleImages/${imageName}')` }}>
  ...
</div>
<img src={`/articleImages/${imageName}`} />

If you aren't using create-react-app config, then you will need to make the images available via however you are serving your application (i.e. express).

Require

This one is a little tricky, and I'm not 100% why it doesn't work out of the box.

What I had to do when testing this was to require all of my images at the top of the file, hard-coded, and then I was able to use the require(stringTemplate) just fine. But I was getting a Error: fileName hasn't been transpiled yet., so I'm not sure if the same fix will work for you.

It basically looks like this:

require('../../../images/articleImages/article1Image.png');
require('../../../images/articleImages/article2Image.png');
... 
// This code would be inside a component
const imageName = 'article2Image.png';
const filePath = '../../../images/articleImages/${imageName}';
const fileUrl = require(filePath);
<div style={{ backgroundImage: `url(${fileUrl})` }}>
  ...
</div>
<img src={fileUrl} />

Without the require(s) at the top of the file, something goes wrong with transpilation.


My suggestion would be go the static assets route which would allow you to use the URL technique above. require is more suited to static files that don't change often like icons.

Feel free to ask any questions, and I'd be happy to clarify and give more examples.