React.js Заменить img src onerror

У меня есть компонент реакции, представляющий собой подробный вид из списка.

Я пытаюсь заменить изображение на изображение по умолчанию, если изображение не существует и есть ошибка 404.

Обычно я использую метод onerror в теге img, но, похоже, он не работает.

Я не уверен, как это сделать с реакцией.

Вот мой компонент:

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;

Ответ 1

Поскольку нет идеального ответа, я публикую фрагмент, который я использую. Я использую многократно используемый компонент Image который используется как fallbackSrc.

Поскольку резервное изображение может снова потерпеть неудачу и вызвать бесконечный цикл повторного рендеринга, я добавил состояние с errored.

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

Ответ 2

Это работает лучше всего для меня

<img src={record.picture} onError={(e)=>{e.target.onerror = null; e.target.src="image_path_here"}}/>

Ответ 3

Вы можете использовать неконтролируемый компонент:

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

Ответ 4

Вам нужно просто определить обработчик onError, чем изменить состояние, которое вызовет метод рендеринга компонента, и в конечном итоге компонент будет повторно рендерить с помощью заполнителя.

Пожалуйста, не используйте jQuery и React вместе!

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;

Ответ 5

Ответ Артура приведет к бесконечным обратным вызовам, если аварийное изображение также не удастся.

Чтобы избежать этого, сначала установите состояние в конструкторе для imageLoadError как true:

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

а затем проверьте это значение состояния в функции onError чтобы избежать бесконечных обратных вызовов,

код будет выглядеть так:

<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';
        }
    }}
/>

Ответ 6

Столкнулся с подобной проблемой, и лучшим решением, которое я смог найти, был ответ Георгия Олейникова. (Не требует создания нового состояния imageLoadError как предложил Нитеш Ранджан в своем ответе)

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

e.target.onerror = null не требуется (и на самом деле не помогает), потому что условие if достаточно для предотвращения бесконечного цикла (если не удается загрузить также резервную копию).

Так:

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

РЕДАКТИРОВАТЬ: Другой способ - установить флаг за скобками возврата и проверить флаг в операторе if. Код должен выглядеть примерно так:

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

Ответ 7

Я взял ответ @Skay и создал многоразовый компонент Image. Проводка в случае, если это кому-то поможет:

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;

Ответ 8

Ответ @DepH хорош, но он создает бесконечный цикл, если ваш источник ошибок также не загружается. Это помогло мне избежать цикла обратного вызова:

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

Ответ 9

Для таких как я, которые также хотели изменить стили элемента и/или изменить источник img, просто сделайте что-то вроде этого:

<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
  }}
/>

Надеюсь, поможет!

Ответ 10

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
 }}
/>

это то, что я сейчас использую.

Ответ 11

Как я это сделал.

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

Ответ 12

Вы можете использовать object если это хорошо с вашим требованием. Что-то вроде ниже будет работать отлично

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

Проверьте этот ответ для получения более подробной информации fooobar.com/questions/47385/...

Ответ 13

Вот ответ с помощью хуков:

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} />
}

И если вы хотите, чтобы справиться с src изменение пропеллер, вы можете передать key опору в 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='...' />

Единственный крайний случай, когда такой ключ может потерпеть неудачу, - это родственные компоненты. Я думаю, что только один родной узел будет отображаться, если они имеют одинаковый ключ. Чтобы обойти это, вы, вероятно, можете обернуть изображение во Fragment <>.

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

Ответ 14

Я написал так.

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

Ответ 15

Если кто-то использует изображение src с require, то onError не работает как -

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

затем выдает ошибку, когда я попробовал несколько способов и пришел, чтобы попытаться найти решение для блока как -

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

и использовать как

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

Ответ 16

это работает для меня.

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

Студент - это имя моего массива и noimage изображения, когда изображение не отображается.