Ich habe eine React-Komponente, die die Detailansicht einer Liste darstellt.
Ich versuche, das Bild durch ein Standardbild zu ersetzen, wenn das Bild nicht vorhanden ist und ein Fehler 404 auftritt.
Normalerweise würde ich die onerror-Methode im img-Tag verwenden, aber das scheint nicht zu funktionieren.
Ich bin mir nicht sicher, wie ich das machen soll.
Hier ist meine Komponente:
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;
Das funktioniert am besten für mich
<img src={record.picture} onError={(e)=>{e.target.onerror = null; e.target.src="image_path_here"}}/>
Sie können eine unkontrollierte Komponente verwenden:
<img src={this.state.img} ref={img => this.img = img} onError={
() => this.img.src = 'img/default.img'
}>
Sie müssen nur den onError-Handler definieren, als den Status zu ändern, der die Komponententrendemethode auslöst, und schließlich wird die Komponente mit Platzhalter erneut gerendert.
Bitte verwenden Sie nicht jQuery und React zusammen!
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;
Arthurs Antwort führt zu unendlichen Rückrufen, wenn das Fallback-Image ebenfalls fehlschlägt.
Um dies zu vermeiden, setzen Sie zunächst einen Status im Konstruktor für imageLoadError auf true:
constructor(props) {
super(props);
this.state = {
imageLoadError: true,
};
}
und prüfen Sie dann diesen Statuswert in der Funktion onError
, um unendliche Rückrufe zu vermeiden.
Der Code sieht so aus: -
<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';
}}
}
/>
@ DepHs Antwort ist Nice, aber es erzeugt eine Endlosschleife, falls Ihre Fehlerquelle ebenfalls nicht geladen wird. Dies half mir, die Callback-Schleife zu vermeiden:
onError={(e)=>{ if (e.target.src !== "image_path_here")
{ e.target.onerror = null; e.target.src="image_path_here"; } }}
Ich nahm die Antwort von @ Skay und erstellte eine wiederverwendbare Image-Komponente. Posting, falls es jemandem hilft:
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;
Ich hatte ein ähnliches Problem und die beste Lösung, die ich finden konnte, war die Antwort von Georgii Oleinikov . (Erfordert keine neuen imageLoadError
-Zustände, wie von Nitesh Ranjan in seiner Antwort vorgeschlagen)
onError={(e)=>{ if (e.target.src !== "image_path_here"){
e.target.onerror = null;
e.target.src="image_path_here";}
}
}
e.target.onerror = null
wird nicht benötigt (und hilft auch nicht wirklich), da die if-Bedingung ausreicht, um die Endlosschleife zu verhindern (falls das Backup-Image ebenfalls nicht geladen wird).
So:
onError={(e)=>{ if (e.target.src !== "image_path_here"){
e.target.src="image_path_here";}
}
}
BEARBEITEN: Die andere Möglichkeit besteht darin, ein Flag außerhalb der zurückgegebenen Klammern zu setzen und das Flag in der if-Anweisung zu überprüfen. Code sollte ungefähr so aussehen:
render(){
let errorflag=true;
return(
<img alt='' src={imageUrl}
onError={(e)=>{ if (errorflag){ errorflag=false; e.target.src=url; } }} />
);
}
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
}}
/>
das verwende ich gerade.
Für diejenigen wie mich, die auch die Stile des Elements und/oder die Quelle img ändern wollten, tun Sie einfach Folgendes:
<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
}}
/>
Ich hoffe es hilft!
Sie können object
verwenden, wenn dies für Ihre Anforderung in Ordnung ist. Etwas wie unten wird perfekt funktionieren
<object data={expected_image} type="image/jpg">
<img src={DEFAULT} alt="404" />
</object>
Weitere Informationen finden Sie in dieser Antwort https://stackoverflow.com/a/29111371/1334182
So habe ich es gemacht.
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}/>;
}
}
Hier ist eine Antwort mit Haken:
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} />
}
Und wenn Sie mit dem Ändern der Requisite src
umgehen möchten, können Sie eine Requisite key
der Requisite src
übergeben. 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='...' />
Der einzige extrem konstruierte Edge-Fall, bei dem die Verwendung eines solchen Schlüssels fehlschlagen könnte, ist die Verwendung von Geschwisterkomponenten. Ich denke, nur ein Geschwisterknoten wird gerendert, wenn er denselben Schlüssel hat. Um dies zu umgehen, könnten Sie das Bild wahrscheinlich in einen <>
Fragment
einwickeln.
<><Image key={srcProp} ... /></>
<><Image key={srcProp} ... /></>
Ich habe so geschrieben.
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);
Da es keine perfekte Antwort gibt, poste ich den Ausschnitt, den ich benutze. Ich verwende eine wiederverwendbare Image
-Komponente, die auf fallbackSrc
zurückgreift.
Da das Fallback-Image erneut fehlschlagen und eine unendliche Schleife für das erneute Rendern auslösen könnte, habe ich den Status errored
hinzugefügt.
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,
};