react.js Replace img src onerror

2020-01-27 15:02发布

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;

16条回答
孤傲高冷的网名
2楼-- · 2020-01-27 15:16

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} ... /></>
查看更多
看我几分像从前
3楼-- · 2020-01-27 15:18
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.

查看更多
Melony?
4楼-- · 2020-01-27 15:19

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;

查看更多
我命由我不由天
5楼-- · 2020-01-27 15:25

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!

查看更多
▲ chillily
6楼-- · 2020-01-27 15:27

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.

查看更多
唯我独甜
7楼-- · 2020-01-27 15:28

@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"; } }}
查看更多
登录 后发表回答