React Fallback for Broken Images Strategy

Dani Shulman
3 min readMar 14, 2018

--

In development, was discovered that an external API returning links to some missing/broken images. It was hurting a custom implementation of Ant Design Carousel. Let’s see what we can do on the front-end to make sure user experience stays good, and we don’t show the broken images.

If you are new to Ant Design, check out this blog about it.

Let’s get back to broken images. The most basic approach would be to use the onError event and replace an image that failed to load with a fallback image. It’s supported by all browsers (compatibility report here).

<img src="image.png" onError="this.onerror=null; this.src='/images/noimage.gif';" />

In React we can also use onError, and trigger a function that can deal with it the broken image.

<img onError={this.addDefaultSrc} className="img-responsive" src={newsImage} alt={headline}/>

//Your handler Component
addDefaultSrc(ev){
ev.target.src = 'some default image url'
}

This approach is elegant, but it does require some changes to our code, in places where we load images with CSS backgroundImage, since our data source was providing images of different sizes, but we needed them all the same size and aspect ratio for a carousel thumbnails.

<customImage style={{ ‘backgroundImage’: “url(“+image+”)” }} />

React Image Component

React Image is an interesting React plugin, with 124K downloads, and is based on the method discussed about, plus some other interesting features:

  • Multiple fallback images
  • Show Gif (animation) while images are loading
  • Fallback element if fallback images fail to load
  • Decode before paint
  • Delay rendering until element is visible (lazy rendering/loading)

CSS background image stack

One other small approach is to include a fallback image in the CSS backgroundImage like so, only in React JSX syntax:

background: image('myimage.gif', 'fallback.gif');

Note that fallback.gif may be downloaded by the browser even if myimage.gif is actually available. It’s ok if you use the same fallback image for many images.

Aspect ratio issue

This is a bit off-topic, but it seemed like in order to fix our loading images failure, we had to solve our aspect ratio challange, and switch from CSS background images to the standard HTML image tags.

React Aspect Ratio Component does exactly that:

import AspectRatio from 'react-aspect-ratio';const RatioImage = () => (  <AspectRatio ratio="3/4" style={{maxWidth: '400px'}}>  <img   src="https://c1.staticflickr.com/4/3896/14550191836_cc0675d906.jpg" />  </AspectRatio>);

This approach will require us to implement two external components, but maybe there is an easier way?

React Approach to hide images that failed to load

getInitialState: function(event) { return {errored: true}; },  handleError: function(event) {   this.setState({errored: true}); },  render: function() {   
if (this.state.errored) {
return null;
} else {
return <img onError={this.handleError} src={src} />;
}
]

The solution

The Ant Design carousel did use the standard IMG html image element. That allowed me to do a callback onError, and pass the key of the broken image.

<Carousel  autoplay  effect="fade"  ref={node => (this.carousel = node)}  {...props}>{this.state.img16x9.map((image, z) => {  return (<img key={z} onError= {() => {    this.handleImage404Error(z);  }} src={image} />)})}</Carousel>

In the handler I filtered the image from the list, and updated state. The CSS thumbnails state object was also filtered in the same handler, and reflected the larger images.

handleImage404Error(key) {  var img16x9 = this.state.img16x9.filter( (item,z) =>  return key !== z;});this.setState({img16x9: img16x9});}

This solution prevented me from loading two external libraries, and was fairly easy to implement. However, I’m not crazy about the need to filter two lists from missing image id’s, and updating the state each time.

Way to go, you got this far…

Your reward is a picture of my cat making a cute face :P

Hopefully my guide was helpful. Please leave a comment, clap, I would love to hear from you.

Dani Shulman
Full-Stack Developer, Consultant
Toronto, Canada
http://iqdev.ca

--

--