react.js Replace img src onerror

JavascriptReactjsHttp Status-Code-404

Javascript Problem Overview


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;

Javascript Solutions


Solution 1 - Javascript

This works best for me

<img 
  src={record.picture}
  onError={({ currentTarget }) => {
    currentTarget.onerror = null; // prevents looping
    currentTarget.src="image_path_here";
  }}
/>

Solution 2 - Javascript

Since there is no perfect answer, I am posting the snippet I use. I am using reusable Image component that fallbacks 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,
};

Solution 3 - Javascript

You can use uncontrolled component:

<img src={this.state.img} ref={img => this.img = img} onError={
    () => this.img.src = 'img/default.img'
}>

Solution 4 - Javascript

2021 Updated Answer using React Functional Components, Hooks and TypeScript

// ImageWithFallback.tsx
import React, { ImgHTMLAttributes, useState } from 'react'

interface Props extends ImgHTMLAttributes<any> {
  fallback: string
}

export default function ImageWithFallback({ fallback, src, ...props }: Props) {
  const [imgSrc, setImgSrc] = useState<string | undefined>(src)
  const onError = () => setImgSrc(fallback)

  return <img src={imgSrc ? imgSrc : fallback} onError={onError} {...props} />
}


Solution 5 - Javascript

Its So Simple

e.target.onerror = null If Error Image Also Fails to Load jsx

<img 
   src={imageSrc}
   onError={(e) => (e.target.onerror = null, e.target.src = imageErrorSrc)}/>

Solution 6 - Javascript

You need just define onError handler than change the state which will trigger component render method and eventually component will re-render with placeholder.

Please, don't use jQuery and React together!

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

onError() {
  this.setState({
    imageUrl: "img/default.png"
  })
}

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

export default Contact;

Solution 7 - Javascript

Arthur's answer will result in infinite callbacks if fallback image also fails.

To avoid that, first set a state in the constructor for imageLoadError as true :

constructor(props) {
    super(props);
    this.state = {
      imageLoadError: true,
    };
}

and then check for this state value in onError function to avoid infinite callbacks,

the code will look like this :-

<img
    src={"https://if_this_url_fails_go_to_onError"}
    onError={e => { 
        if(this.state.imageLoadError) { 
            this.setState({
                imageLoadError: false
            });
            e.target.src = 'fallbackImage.png';
        }
    }}
/>

Solution 8 - Javascript

@DepH's answer is nice, but it does produce and infinite loop if your error source also doesn't load. This helped me avoid the callback loop:

onError={(e)=>{ if (e.target.src !== "image_path_here") 
    { e.target.onerror = null; e.target.src="image_path_here"; } }}

Solution 9 - Javascript

import OriginalImage from '../../originalImg.png'
import ReplacementImage from '../../replaceImg.png'

<img
 src= OriginalImage
 alt="example"
 onError={(e) => {
    e.target.src = ReplacementImage //replacement image imported above
    e.target.style = 'padding: 8px; margin: 16px' // inline styles in html format
 }}
/>

this is what I'm currently using.

Solution 10 - Javascript

Ran into a similar problem and the best solution i could find was Georgii Oleinikov's answer. (Doesn't require making new imageLoadError state as suggested by Nitesh Ranjan in his answer)

onError={(e)=>{ if (e.target.src !== "image_path_here"){
                    e.target.onerror = null;
                     e.target.src="image_path_here";}
                }
           }

e.target.onerror = null is not needed (and doesn't really help) because the if condition is enough to prevent the infinite loop(if backup image fails to load as well).

So:

onError={(e)=>{ if (e.target.src !== "image_path_here"){
                 e.target.src="image_path_here";}
               }
         }

EDIT: The other way around is to set a flag outside the return brackets and check for the flag in the if statement. Code should look something like this:

render(){
 let errorflag=true;
 return(
			<img alt='' src={imageUrl} 
 					onError={(e)=>{ if (errorflag){ errorflag=false; e.target.src=url; } }} />
 			);
} 

Solution 11 - Javascript

Here's an answer using hooks:

import React, { useState } from 'react'

/**
 * Returns an object that can 
 * be spread onto an img tag
 * @param {String} img
 * @param {String} fallback
 * @returns {Object} { src: String, onError: Func }
*/
function useFallbackImg(img, fallback) {
  const [src, setImg] = useState(img)
  
  function onError(e) {
    console.log('Missing img', img, e)
    // React bails out of hook renders if the state
    // is the same as the previous state, otherwise
    // fallback erroring out would cause an infinite loop
    setImg(fallback)
  }

  return { src, onError }
}

/**
 * Usage <Image src='someUrl' fallback='fallbackUrl' alt='something' />
 */
function Image({src, fallback, ...rest}) {
  
  const imgProps = useFallbackImg(src, fallback)
  
  return <img {...imgProps} {...rest} />
}

And if you are want to handle the src prop changing, you can pass a key prop of the src. https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html#recommendation-fully-uncontrolled-component-with-a-key

<Image key='someUrl' src='someUrl' fallback='fallbackUrl' alt='...' />

The only extreme contrived edge case where using a key like this might fail is with sibling components. I think only one sibling node will render if they have the same key. To get around this you could probably wrap the Image in a <> Fragment.

<><Image key={srcProp} ... /></>
<><Image key={srcProp} ... /></>

Solution 12 - Javascript

I wrote like this.

import React, { useState } from 'react';
import NoImageSVG from './noImage.svg';

const ImgWithFallback: React.FunctionComponent<{ src: string; alt: string; className: string }> = ({
  src,
  alt,
  className,
}) => {
  const [isUndefined, updateIsUndefined] = useState(false);

  const onError = () => {
    updateIsUndefined(true);
  };

  if (isUndefined) {
    return (
      <div className={className}>
        <NoImageSVG width='5rem' height='5rem' />
      </div>
    );
  }

  return <img src={src} alt={alt} className={className} onError={onError} />;
};

export default React.memo(ImgWithFallback, () => true);

Solution 13 - Javascript

I took @Skay's answer and created a reusable Image component. Posting in case it helps anyone:

import React, { PropTypes } from 'react';

const Image = ({src, fallbackSrc, ...other}) => {
    let element;
    const changeSrc = newSrc => {
        element.src = newSrc;
    };
    return (
        <img src={src} 
             onError={() => changeSrc(fallbackSrc)} 
             ref={el => element=el} 
             {...other} />
    );
};

Image.propTypes = {
    src: PropTypes.string,
    fallbackSrc: PropTypes.string
};
export default Image;

Solution 14 - Javascript

Even though this is an old question if you are looking of a clean solution you can use react-image-fallback library.

<ReactImageFallback
                    src="my-image.png"
                    fallbackImage="my-backup.png"
                    initialImage="loader.gif"
                    alt="cool image should be here"
                    className="my-image" />

react-image-fallback

Solution 15 - Javascript

For those like me who also wanted to change the styles of the element and/or change the img source, just do something like this:

<img
  src={'original src url goes here'}
  alt="example"
  onError={(e) => {
     e.target.src = '/example/noimage.png' // some replacement image
     e.target.style = 'padding: 8px; margin: 16px' // inline styles in html format
  }}
/>

Hope it helps!

Solution 16 - Javascript

I used the above method of Arthurs making e.target.onerror = null to stop the infinite loop , but still the infinite loop happened. So , to stop the infinite loop I had to use the below method.I had to find the actual property onError and make it null.

<img src={imageSource}
     onError={(e) => { 
              e.target[Object.keys(e.target).filter(prop=>prop.includes('EventHandler'))[0]].onError = null;
              e.target.src = 'images/avatar.png'; }}
 />

event.target properties

Solution 17 - Javascript

For SSR (Server Side Rendering)...

So, here's a workaround that works (for me)!

const Img: FC<
  DetailedHTMLProps<ImgHTMLAttributes<HTMLImageElement>, HTMLImageElement>
> = ({ src, ...props }): JSX.Element => {
  const [hasRendered, setHasRendered] = useState(false);
  const imgRef = useRef<HTMLImageElement | null>(null);

  useEffect(() => {
    if (imgRef.current && hasRendered) {
      imgRef.current!.src = src || '';
    }
  }, [src, hasRendered]);

  useEffect(() => {
    setHasRendered(true);
  }, []);

  return (
    <img
      {...props}
      ref={imgRef as any}
      alt={props.alt || 'image'}
      aria-hidden={true}
      onError={...}
      onLoad={...}
    />
  );
};

So, the magic happens in the two useEffect hooks. (Using just one didn't work). Basically, the second useEffect ensures the first hook is triggered (or component re-renders) a second time (after initial render), due to the hasRendered dep, which then forces the image src to be set in that hook which then triggers the events on the client!

Solution 18 - Javascript

That's how I did it.

 class Pix extends React.Component{
    
          constructor(props){
            super(props);
           this.state={link: this.props.link};
           this.onError=this.onError.bind(this);
          }
    
          
          onError(){
              console.log("error: could not find picture");
              this.setState(function(){ return {link: "missing.png"}; });
             };
     
          render(){
          return <img onError={this.onError} src={this.state.link}/>;
          } 
    }

Solution 19 - Javascript

You can use object if that's ok with your requirement. Something like below will work perfectly fine

<object data={expected_image} type="image/jpg">
  <img src={DEFAULT} alt="404" />
</object>

Check this answer for more details https://stackoverflow.com/a/29111371/1334182

Solution 20 - Javascript

If anyone is using image src with require then onError doesn't work as -

<img src={require(`./../../assets/images/${props.imgName}.png`)} className="card-img" alt={props.name} />

then require throws an error, where I tried multiple ways and came to try and catch block solution as -

  let imgSrc;
  try {
    imgSrc = require(`./../../assets/images/${props.imgName}.png`);  
  } catch {
    imgSrc = require(`./../../assets/images/default.png`);
  }

and use as

<img src={imgSrc} className="card-img" alt={props.name} />

Solution 21 - Javascript

Previous versions have the bug; they don't count that src could be changed. So I made my ultimate solution and it:

  1. Supports typing
  2. Support case when src is changed
  3. Forwards ref
  4. Doesn't ignore onError (means you can pass onError to ImageWithFallback like you usually do with <img />)

Here it is:

import React, { useState, useCallback, useEffect } from 'react';
import noImage from 'src/svg/no-image.svg';

export const ImageWithFallback = React.forwardRef(
  (
    {
      onError,
      ...props
    }: React.DetailedHTMLProps<
      React.ImgHTMLAttributes<HTMLImageElement>,
      HTMLImageElement
    >,
    ref: React.Ref<HTMLImageElement>,
  ) => {
    const [imageLoadFailed, setImageLoadFailed] = useState<boolean>(false);

    const handleError = useCallback(
      (e: React.SyntheticEvent<HTMLImageElement, Event>) => {
        if (imageLoadFailed) return;
        setImageLoadFailed(true); // to avoid infinite loop
        if (onError) {
          onError(e);
        }
      },
      [imageLoadFailed, setImageLoadFailed, onError],
    );

    useEffect(() => {
      setImageLoadFailed(false); // in case `src` is changed
    }, [props.src]);

    return (
      <img
        {...props}
        src={imageLoadFailed ? noImage : props.src}
        onError={handleError}
        ref={ref}
      />
    );
  },
);

Solution 22 - Javascript

As it was mentioned in one of the comments, the best solution is to use react-image library. Using onError will fail when you try to serve static version of your react website after build.

Here is super simple and straightforward example how to use react-image, just import Img component

import {Img} from 'react-image'

And later specify a list of src that you try to load

<Img
   src={['images/image1.svg', 'images/default.svg']}
   alt="Some title"
/>   

If 1st url not found, the 2nd will be loaded, there are also some other pretty cool features like showing a spinner while image is loading or displaying some other component in case none of the listed images are available

Solution 23 - Javascript

Try this custom Image component:

import React, { useRef } from 'react';
import PropTypes from 'prop-types';

import defaultErrorImage from 'assets/images/default-placeholder-image.png';

const Image = ({ src, alt, className, onErrorImage }) => {
  const imageEl = useRef(null);
  return (
    <img
      src={src}
      alt={alt}
      className={className}
      onError={() => {
        imageEl.current.src = onErrorImage;
      }}
      ref={imageEl}
    />
  );
};

Image.defaultProps = {
  onErrorImage: defaultErrorImage,
};

Image.propTypes = {
  src: PropTypes.string.isRequired,
  alt: PropTypes.string.isRequired,
  className: PropTypes.string.isRequired,
  onErrorImage: PropTypes.string,
};

export default Image;

Solution 24 - Javascript

Typescript version:

const Avatar = (): JSX.Element => {
    function imageErrorHandler(e: React.SyntheticEvent<HTMLImageElement, Event>) {
      const el = e.target as HTMLImageElement
      el.onerror = null
      el.src = '/fallback.png'
    }

    return <img src={'/smth.png'} onError={imageErrorHandler}/>
  },
)

With forwardRef and possible null src:

import { forwardRef } from 'react'

type Props = Omit<React.ComponentPropsWithoutRef<'img'>, 'src'> & { src?: null | string }

const Avatar = forwardRef<HTMLImageElement, Props>(
  ({ src, ...rest }, ref): JSX.Element => {
    function imageErrorHandler(e: React.SyntheticEvent<HTMLImageElement, Event>) {
      const el = e.target as HTMLImageElement
      el.onerror = null
      el.src = '/fallback.png'
    }

    return <img src={src || '/alternative.png'} onError={imageErrorHandler} ref={ref} {...rest} />
  },
)

Solution 25 - Javascript

With the help of @emil's solution above I created this little functional component. It's using a fallback src on First error and removing the img on second error, from fallback src.

import React, { useState } from 'react'

function ImageFallback({ src, fallbackSrc, ...props }) {

    const [state, setState] = useState({ src: src, errored: false })
   

    //update(next img) state onMount 
    useEffect(() => {
       setState({
           src: src,
           errored: false,
       })

    }, [src])

   //update (remove) state onUnMount
   useEffect(() => {
       return () => {
           setState({
               src: null,
               errored: false,
           })
       }
   }, [])

    const onError = () => {
        //1st error
        if (!state.errored) {
            setState({
                src: fallbackSrc,
                errored: true,
            });
        } else if (state.errored && state.src) {
            //2nd error
            //when error on fallbacksrc - remove src
            setState({
                src: null,
                errored: true,
            });
        }

    }

    return (
        state.src && <img
            src={state.src}
            onError={onError}
            {...props}
        />
    )
}

export default ImageFallback

Usage ...

 <ImageFallback src={anySrc} fallbackSrc={anyFallbackSrc} className={classes.logo} alt='' />

Solution 26 - Javascript

I expanded @Emils solution using TypeScript and added

  • placeholder support while loading
import * as React from "react";

type Props = {
    src: string,
    fallbackSrc: string,
    placeholderColor?: string,
    className?: string,
}

type State = {
    src: string,
    errored: boolean,
    loaded: boolean
}

export default class Image extends React.Component<Props, State> {
    constructor(props: Props) {
        super(props);

        this.state = {
            src: props.src,
            errored: false,
            loaded: false
        };
    }

    onError = () => {
        if (!this.state.errored) {
            this.setState({
                src: this.props.fallbackSrc,
                errored: true,
            });
        }
    }

    onLoad = () => {
        if(!this.state.loaded){
            this.setState({loaded: true});
        }
    }

    render() {
        let style = {
            backgroundColor: this.props?.placeholderColor || "white"
        };

        if(this.state.loaded){
            style.backgroundColor = "transparent";
        }

        return (
            <img
                style={style}
                onLoad={this.onLoad}
                onError={this.onError}
                {...this.props}
                src={this.state.src}
            />
        );
    }
}

Solution 27 - Javascript

this works for me .

{<img className="images"
    src={`/images/${student.src ? student.src : "noimage.png" }`} alt=  
{student.firstname} />} 

student is the name of my array and noimage the image, when there is no image is display.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJoel LawlerView Question on Stackoverflow
Solution 1 - JavascriptDeepak MallahView Answer on Stackoverflow
Solution 2 - JavascriptemilView Answer on Stackoverflow
Solution 3 - JavascriptK.ArthurView Answer on Stackoverflow
Solution 4 - JavascriptMarcosView Answer on Stackoverflow
Solution 5 - JavascriptKabeer JaffriView Answer on Stackoverflow
Solution 6 - JavascriptSkayView Answer on Stackoverflow
Solution 7 - JavascriptNitesh RanjanView Answer on Stackoverflow
Solution 8 - JavascriptGeorgii OleinikovView Answer on Stackoverflow
Solution 9 - JavascriptMrinmayView Answer on Stackoverflow
Solution 10 - JavascriptSaurabh ChauhanView Answer on Stackoverflow
Solution 11 - JavascriptjtcView Answer on Stackoverflow
Solution 12 - JavascriptR. M.View Answer on Stackoverflow
Solution 13 - JavascriptKevinView Answer on Stackoverflow
Solution 14 - JavascriptChathurika SandarenuView Answer on Stackoverflow
Solution 15 - JavascriptGustavo GarciaView Answer on Stackoverflow
Solution 16 - JavascriptMOHANTEJAView Answer on Stackoverflow
Solution 17 - JavascriptSunday Power InemesitView Answer on Stackoverflow
Solution 18 - JavascriptMatthias LisztView Answer on Stackoverflow
Solution 19 - JavascriptS4beRView Answer on Stackoverflow
Solution 20 - JavascriptNiksView Answer on Stackoverflow
Solution 21 - JavascriptquolprView Answer on Stackoverflow
Solution 22 - JavascriptAlexander CherednichenkoView Answer on Stackoverflow
Solution 23 - JavascriptJorge Luis MonroyView Answer on Stackoverflow
Solution 24 - JavascriptZiiMakcView Answer on Stackoverflow
Solution 25 - JavascriptSyed Zain JeelaniView Answer on Stackoverflow
Solution 26 - JavascriptsakramentoView Answer on Stackoverflow
Solution 27 - JavascriptYasir AkbarView Answer on Stackoverflow