82

I've been trying to figure out how to dynamically add images via React and Webpack. I have an image folder under src/images and a component under src/components/index. I'm using url-loader with the following config for webpack

    {
      test: /\.(png|jpg|)$/,
      loader: 'url-loader?limit=200000'
    }

Within the component I know I can add require(image_path) for a specific image at the top of the file before I create the component but I want make the component generic and have it take a property with the path for the image that is passed from the parent component.

What I have tried is:

<img src={require(this.props.img)} />

For the actual property I have tried pretty much every path I can think of to the image from the project root, from the react app root, and from the component itself.

Filesystem

|-- src
|   ` app.js
|   `--images
|      ` image.jpg
|      ` image.jpg
|   `-- components
|      `parent_component.js
|      `child_component.js

The parent component is basically just a container to hold multiples of the child so...

<ChildComponent img=data.img1 />
<ChildComponent img=data.img2 />
etc....

Is there any way in which to do this using react and webpack with url-loader or am I just going down a wrong path to approach this?

7 Answers 7

102

Using url-loader, described here (SurviveJS - Loading Images), you can then use in your code :

import LogoImg from 'YOUR_PATH/logo.png';

and

<img src={LogoImg}/>

Edit: a precision, images are inlined in the js archive with this technique. It can be worthy for small images, but use the technique wisely.

6
  • 1
    I wish to know how to load this image from and API that returns the image.
    – The Oracle
    Commented Dec 7, 2016 at 15:39
  • 3
    I'm not sure to undertand : if you want the user browser to load the image from an API, it has nothing to do with webpack. Just use a variable (probably defined after a call to the API) as the <img> src. The idea here was to include the image in your sources and webpack archive. (see stackoverflow.com/questions/32612912/… )
    – mlorber
    Commented Dec 8, 2016 at 16:01
  • 1
    Thanks, this works great. The article you cited also mentions at the end if you are using React, then you use babel-plugin-transform-react-jsx-img-import to generate the import automatically. that way you can just write <img src="YOUR_PATH/logo.png"/> Commented Jun 17, 2017 at 14:09
  • Warning: url-loader will inline the image file as a base64 ascii string. This decreases the number of file-accesses needed to load a page, but at the cost of more bytes to download. So, may be better to use file-loader for production. Commented Jul 30, 2019 at 21:03
  • Yes, images are inlined with this technique. It completely depends on the weight of the file. For small ones (icons mainly for me), it can be worthy. I'll edit the response
    – mlorber
    Commented Aug 2, 2019 at 7:07
26

If you are bundling your code at the server-side, then there is nothing stopping you from requiring assets directly from jsx:

<div>
  <h1>Image</h1>
  <img src={require('./assets/image.png')} />
</div>
4
  • 3
    This is what I needed to use for my situation where I don't know the image file until the component is built. I pass in an imageFilename prop and then use <img src={require(`./images/${imageFilename}`)} />. Thanks for posting. Commented Feb 18, 2017 at 6:32
  • 1
    @BrendanMoore but remember that in your case a bundler (say webpack) will add all images from the images folder to the final bundle. Commented Feb 21, 2017 at 12:31
  • 1
    Exactly what I was looking for. Thanks @JamesAkwuh Commented Jun 13, 2019 at 12:38
  • 16
    If this isn't working, then add .default after require(). Eg: I'm using like const src = require(assets/images/${name}).default; Commented Aug 29, 2020 at 15:30
13

UPDATE: this only tested with server side rendering ( universal Javascript ) here is my boilerplate.

With only file-loader you can load images dynamically - the trick is to use ES6 template strings so that Webpack can pick it up:

This will NOT work. :

const myImg = './cute.jpg'
<img src={require(myImg)} />

To fix this, just use template strings instead :

const myImg = './cute.jpg'
<img src={require(`${myImg}`)} />

webpack.config.js :

var HtmlWebpackPlugin =  require('html-webpack-plugin')
var ExtractTextWebpackPlugin = require('extract-text-webpack-plugin')

module.exports = {
  entry : './src/app.js',
  output : {
    path : './dist',
    filename : 'app.bundle.js'
  },
  plugins : [
  new ExtractTextWebpackPlugin('app.bundle.css')],
  module : {
    rules : [{
      test : /\.css$/,
      use : ExtractTextWebpackPlugin.extract({
        fallback : 'style-loader',
        use: 'css-loader'
      })
    },{
      test: /\.js$/,
      exclude: /(node_modules)/,
      loader: 'babel-loader',
      query: {
        presets: ['react','es2015']
      }
    },{
      test : /\.jpg$/,
      exclude: /(node_modules)/,
      loader : 'file-loader'
    }]
  }
}
1
  • 2
    Missing piece for me was the test in the webpack config. thanks. Commented Feb 22, 2018 at 21:44
12

If you are looking for a way to import all your images from the image

// Import all images in image folder
function importAll(r) {
    let images = {};
    r.keys().map((item, index) => { images[item.replace('./', '')] = r(item); });
    return images;
}

const images = importAll(require.context('../images', false, /\.(gif|jpe?g|svg)$/));

Then:

<img src={images['image-01.jpg']}/>

You can find the original thread here: Dynamically import images from a directory using webpack

6

So you have to add an import statement on your parent component:

class ParentClass extends Component {
  render() {
    const img = require('../images/img.png');
    return (
      <div>
        <ChildClass
          img={img}
        />
      </div>
    );
  }
}

and in the child class:

class ChildClass extends Component {
  render() {
    return (
      <div>
          <img
            src={this.props.img}
          />
      </div>
    );
  }
}
3

You do not embed the images in the bundle. They are called through the browser. So its;

var imgSrc = './image/image1.jpg';

return <img src={imgSrc} />
3
  • 3
    but what if you don't know the image at build time? What if the image URL is composed at runtime?
    – JBCP
    Commented Dec 7, 2015 at 15:21
  • The goal of the loader you're using is actually to NOT using an url in your code, and being potentially able to embed the image in the archive if it's small enough (better perfs)
    – mlorber
    Commented Feb 17, 2016 at 11:00
  • @JBCP Exactly e.g React adding unique suffix to image name
    – besthost
    Commented Sep 4, 2023 at 6:34
2

here is the code

    import React, { Component } from 'react';
    import logo from './logo.svg';
    import './image.css';
    import Dropdown from 'react-dropdown';
    import axios from 'axios';

    let obj = {};

    class App extends Component {
      constructor(){
        super();
        this.state = {
          selectedFiles: []
        }
        this.fileUploadHandler = this.fileUploadHandler.bind(this);
      }

      fileUploadHandler(file){
        let selectedFiles_ = this.state.selectedFiles;
        selectedFiles_.push(file);
        this.setState({selectedFiles: selectedFiles_});
      }

      render() {
        let Images = this.state.selectedFiles.map(image => {
          <div className = "image_parent">

              <img src={require(image.src)}
              />
          </div>
        });

        return (
            <div className="image-upload images_main">

            <input type="file" onClick={this.fileUploadHandler}/>
            {Images}

            </div>
        );
      }
    }

    export default App;

Not the answer you're looking for? Browse other questions tagged or ask your own question.