Search code examples
javascriptreactjshttp-status-code-404

react.js Replace img src onerror


I have a react component that is the detail view from a list.

I am trying to replace the image with a default image if the image does not exist and there is a 404 error.

I would normally use the onerror method in the img tag but that doesn't seem to be working.

I am not sure how to do this with react.

Here is my component:

import React from 'react';
import {Link} from 'react-router';
import ContactStore from '../stores/ContactStore'
import ContactActions from '../actions/ContactActions';

class Contact extends React.Component {
  constructor(props) {
    super(props);
    this.state = ContactStore.getState();
    this.onChange = this.onChange.bind(this); 
 }

componentDidMount() {
  ContactStore.listen(this.onChange);
  ContactActions.getContact(this.props.params.id);
}

componentWillUnmount() {
  ContactStore.unlisten(this.onChange);
}

componentDidUpdate(prevProps) {
  if (prevProps.params.id !== this.props.params.id) {
    ContactActions.getContact(this.props.params.id);
  }
}

onChange(state) {
  this.setState(state);
}

render() {
  return (
    <div className='container'>
      <div className='list-group'>
        <div className='list-group-item animated fadeIn'>
          <h4>{this.state.contact.displayname}</h4>
          <img src={this.state.imageUrl} />
        </div>
      </div>
    </div>
  );
}
}

export default Contact;

Solution

  • Since there is no perfect answer, I am posting the snippet I use. I am using reusable Image component that falls back to fallbackSrc.

    Since the fallback image could fail again and trigger infinite loop of re-rendering, I added errored state.

    import React, { Component } from 'react';
    import PropTypes from 'prop-types';
    
    class Image extends Component {
      constructor(props) {
        super(props);
    
        this.state = {
          src: props.src,
          errored: false,
        };
      }
    
      onError = () => {
        if (!this.state.errored) {
          this.setState({
            src: this.props.fallbackSrc,
            errored: true,
          });
        }
      }
    
      render() {
        const { src } = this.state;
        const {
          src: _1,
          fallbackSrc: _2,
          ...props
        } = this.props;
    
        return (
          <img
            src={src}
            onError={this.onError}
            {...props}
          />
        );
      }
    }
    
    Image.propTypes = {
      src: PropTypes.string,
      fallbackSrc: PropTypes.string,
    };