Dynamically Add Images React Webpack
Asked Answered
M

7

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?

Matty answered 16/9, 2015 at 15:31 Comment(0)
C
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.

Carabin answered 17/2, 2016 at 11:2 Comment(6)
I wish to know how to load this image from and API that returns the image.Pencil
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 #32613412 )Carabin
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"/>Lingle
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.Abulia
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 responseCarabin
If you are comfortable using images as inline, just use the inbuilt config of webpack – type: 'asset/inline'. This will increase the file size though.Illustrious
R
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>
Recapitulate answered 24/9, 2016 at 13:0 Comment(4)
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.Illhumored
@BrendanMoore but remember that in your case a bundler (say webpack) will add all images from the images folder to the final bundle.Recapitulate
Exactly what I was looking for. Thanks @JamesAkwuhMineralogy
If this isn't working, then add .default after require(). Eg: I'm using like const src = require(assets/images/${name}).default;Tercentenary
U
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'
    }]
  }
}
Unlikely answered 24/7, 2017 at 3:34 Comment(1)
Missing piece for me was the test in the webpack config. thanks.Heida
G
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

Geiss answered 11/5, 2018 at 11:50 Comment(0)
E
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>
    );
  }
}
Energumen answered 16/6, 2016 at 7:42 Comment(0)
A
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} />
Ause answered 16/9, 2015 at 16:21 Comment(3)
but what if you don't know the image at build time? What if the image URL is composed at runtime?Domesday
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)Carabin
@Domesday Exactly e.g React adding unique suffix to image nameObscenity
R
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;
Raleighraley answered 24/6, 2018 at 6:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.