3

I am creating a React component that randomly cycles through a large number of background images. From my understanding, I could ignore Webpack here and just dynamically generate the require/import statements and pass them to the component.

However, if I want Webpack to use a loader and generate hashes, etc - I haven't found a solution.

This question is similar, but the responses don't address the problem: Dynamically Add Images React Webpack

My current solution involves just requiring all of the images in the component - however, I'm wondering what the 'costs' of this are - just an increased bundle size? Attached is sample code to demonstrate what I mean:

import React from 'react';
import styles from './Background.css';

const pic0 = require('./imgs/0.jpg');
const pic1 = require('./imgs/1.jpg');
const pic2 = require('./imgs/2.jpg');
const pic3 = require('./imgs/3.jpg');
// etc etc etc

class Background extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      pic: {},
    };
    this.changeBackground = this.changeBackground.bind(this);
  }

  componentWillMount() {
    this.setState({ pic: pic0 });
  }

  componentDidMount() {
    // set timeout here
  }

  changeBackground() {
    // change background via component state here
  }

  render() {
    return (
        <img className={styles.background} src={this.state.pic} />
    );
  }
}

export default Background;

Thoughts? Any help would be greatly appreciated.

Community
  • 1
  • 1
Conan
  • 670
  • 7
  • 12

1 Answers1

6

It depends on which loader you configure webpack to use to load these images.

url-loader

When you use url loader, the contents of the image will be base64-encoded and embedded in your JavaScript bundle.

Thus the more images you require, the larger the bundle that the browser must download initially. The advantage is that all of the images are loaded in the browser and can display immediately.

file-loader

When you use file-loader, the image file is copied to your distribution folder (and usually renamed with a content hash) and the URL of the image is stored in your JavaScript bundle.

Requiring a lot of images has very little impact on the size of your JavaScript bundle. The app starts faster. The downside is that the browser will have to fetch the images from the server on demand as you display them.

Summary

url-loader: larger JS bundle, all images display instantly, harder to leverage image cache

file-loader: smaller JS bundle, images individually retrieved when displayed, makes better use of image cache.

Based on your problem statement (randomly cycle through large number of images), I'd start with file-loader.

The good news is your JS code is unchanged either way: you just treat the imported images as URLs either way. Its just a webpack reconfiguration if you change your mind.

Since you have a whole folder of images, I'd also recommend making use of webpack context to essentially require the whole folder in one line:

const imageReq = require.context("./imgs", false, /\.jpg$/);

setUrl(i) {
   // "require" a specific image e.g. "./4.jpg"
   const url = imageReq(`./${i}.jpg`);
   this.setState({pic: url});
}

// ...
Brandon
  • 38,310
  • 8
  • 82
  • 87