react.js Replace img src onerror

后端 未结 22 2961
北恋
北恋 2020-11-29 00:20

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 er

相关标签:
22条回答
  • 2020-11-29 01:02

    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

    0 讨论(0)
  • 2020-11-29 01:03

    @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"; } }}
    
    0 讨论(0)
  • 2020-11-29 01:03

    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} ... /></>
    
    0 讨论(0)
  • 2020-11-29 01:03

    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}/>;
              } 
        }
    
    0 讨论(0)
  • 2020-11-29 01:06

    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} />
    
    0 讨论(0)
  • 2020-11-29 01:06

    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}
          />
        );
      },
    );
    
    0 讨论(0)
提交回复
热议问题