Dynamically Add Images React Webpack

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?

141650 次浏览

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} />

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.

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>
);
}
}

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>

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'
}]
}
}

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

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;