web-dev-qa-db-fra.com

react.js Remplacer img src onerror

J'ai un composant de réaction qui est la vue détaillée d'une liste.

J'essaie de remplacer l'image par une image par défaut si l'image n'existe pas et qu'il y a une erreur 404. 

J'utiliserais normalement la méthode onerror dans la balise img, mais cela ne semble pas fonctionner.

Je ne sais pas comment faire avec Réagir.

Voici mon composant:

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;
26
Joel Lawler

Cela fonctionne mieux pour moi

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

Vous pouvez utiliser un composant non contrôlé:

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

Vous devez simplement définir le gestionnaire onError avant de modifier l’état qui déclenchera la méthode de rendu du composant et, éventuellement, le composant sera rendu à nouveau avec un espace réservé.

S'il vous plaît, n'utilisez pas jQuery et réagissez ensemble!

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;
6
Skay

La réponse d'Arthur entraînera des rappels infinis si l'image de secours échoue également.

Pour éviter cela, définissez d'abord un état dans le constructeur pour imageLoadError sur true:

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

puis recherchez cette valeur d'état dans la fonction onError pour éviter des rappels infinis, 

le code ressemblera à ceci: -

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

La réponse de @ DepH est Nice, mais elle produit une boucle infinie si votre source d'erreur ne se charge pas non plus. Cela m'a aidé à éviter la boucle de rappel:

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

J'ai pris la réponse de @ Skay et créé un composant Image réutilisable. Publier au cas où cela aiderait quelqu'un:

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;

2
Kevin

Couru dans un problème similaire et la meilleure solution que j'ai pu trouver était la réponse de Georgii Oleinikov . (Ne nécessite pas de créer un nouvel état imageLoadError comme suggéré par Nitesh Ranjan dans sa réponse)

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

e.target.onerror = null n'est pas nécessaire (et n'aide pas vraiment) car la condition if suffit à empêcher la boucle infinie (si le chargement de l'image de sauvegarde échoue également).

Alors:

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

EDIT: L’inverse est de placer un drapeau en dehors des crochets et de vérifier le drapeau dans l’instruction if. Le code devrait ressembler à ceci:

render(){
 let errorflag=true;
 return(
            <img alt='' src={imageUrl} 
                    onError={(e)=>{ if (errorflag){ errorflag=false; e.target.src=url; } }} />
            );
} 
2
Saurabh Chauhan
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
 }}
/>

c'est ce que j'utilise actuellement.

1
Mrinmay

Pour ceux qui, comme moi, souhaitent également modifier les styles de l'élément et/ou modifier la source img, procédez comme suit:

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

J'espère que ça aide!

1
Gustavo Garcia

Vous pouvez utiliser object si cela vous convient. Quelque chose comme ci-dessous fonctionnera parfaitement bien

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

Cochez cette réponse pour plus de détails https://stackoverflow.com/a/29111371/1334182

0
S4beR

C'est comme ça que je l'ai fait. 

 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
Matthias Liszt

Puisqu'il n'y a pas de réponse parfaite, je publie l'extrait de code que j'utilise. J'utilise un composant Image réutilisable qui se replie sur fallbackSrc.

Comme l'image de repli pouvait à nouveau échouer et déclencher une boucle infinie de restitution, j'ai ajouté l'état 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,
};

0
emil