我有一个react组件,它是列表中的详细信息视图。
如果图像不存在且存在404错误,我试图用默认图像替换图像。
我通常会在img标签中使用onerror方法,但这似乎并没有起作用。
我不知道怎么做反应。
这是我的组件:
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;
答案 0 :(得分:68)
这最适合我
<img src={record.picture} onError={(e)=>{e.target.onerror = null; e.target.src="image_path_here"}}/>
答案 1 :(得分:12)
您可以使用不受控制的组件:
<img src={this.state.img} ref={img => this.img = img} onError={
() => this.img.src = 'img/default.img'
}>
答案 2 :(得分:8)
您只需定义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;
答案 3 :(得分:5)
2021 年使用 React 功能组件、钩子和 TypeScript 更新答案
// ImageWithFallback.tsx
import React, { ImgHTMLAttributes, useState } from 'react'
interface Props extends ImgHTMLAttributes<any> {
fallback: string
}
export default function ImageWithFallback({ fallback, src, ...props }: Props) {
const [imgSrc, setImgSrc] = useState<string | undefined>(src)
const onError = () => setImgSrc(fallback)
return <img src={imgSrc ? imgSrc : fallback} onError={onError} {...props} />
}
答案 4 :(得分:4)
遇到类似的问题,而我能找到的最佳解决方案是 Georgii Oleinikov 的答案。 ((不需要 Nitesh Ranjan 在他的回答中建议的)建立新的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; } }} />
);
}
答案 5 :(得分:4)
如果后备图像也失败,亚瑟的答案将导致无限的回调。
为避免这种情况,请首先在构造函数中将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 :(得分:3)
@DepH的答案很好,但是如果您的错误源也没有加载,它确实会产生无限循环。这有助于我避免回调循环:
import sqlite3
db=sqlite3.connect('E:/CLYDE/sqlite new2/dbase.db')
cursor=db.cursor()
cursor.execute('''CREATE TABLE users(id INTEGER PRIMARY KEY, name TEXT,
phone TEXT, email TEXT unique, password TEXT)''')
db.commit()
name1 = 'Andres'
phone1 = '3366858'
email1 = 'user@example.com'
# A very secure password
password1 = '12345'
name2 = 'John'
phone2 = '5557241'
email2 = 'johndoe@example.com'
password2 = 'abcdef'
users = [(name1,phone1, email1, password1),
(name2,phone2, email2, password2)]
cursor.executemany(''' INSERT INTO users(name, phone, email, password) VALUES(?,?,?,?)''', users)
db.commit()
答案 7 :(得分:2)
我接受了@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 :(得分:2)
即使这是一个老问题,如果您正在寻找一个干净的解决方案,也可以使用react-image-fallback
库。
<ReactImageFallback
src="my-image.png"
fallbackImage="my-backup.png"
initialImage="loader.gif"
alt="cool image should be here"
className="my-image" />
答案 9 :(得分:2)
我使用上述Arthurs的方法使e.target.onerror = null停止了无限循环,但仍然发生了无限循环。因此,要停止无限循环,我必须使用以下方法。我必须找到实际的属性onError并将其设置为null。
<img src={imageSource}
onError={(e) => {
e.target[Object.keys(e.target).filter(prop=>prop.includes('EventHandler'))[0]].onError = null;
e.target.src = 'images/avatar.png'; }}
/>
答案 10 :(得分: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,
};
答案 11 :(得分:1)
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
}}
/>
这是我目前正在使用的。
答案 12 :(得分:1)
对于像我这样也希望更改元素样式和/或更改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
}}
/>
希望有帮助!
答案 13 :(得分:1)
e.target.onerror = null
如果错误图像也无法加载
jsx
<img
src={imageSrc}
onError={(e) => (e.target.onerror = null, e.target.src = imageErrorSrc)}/>
答案 14 :(得分:0)
借助上面@emil 的解决方案 我创建了这个小功能组件。它在第一个错误时使用后备 src,并从后备 src 中删除第二个错误时的 img。
import React, { useState } from 'react'
function ImageFallback({ src, fallbackSrc, ...props }) {
const [state, setState] = useState({ src: src, errored: false })
//update(next img) state onMount
useEffect(() => {
setState({
src: src,
errored: false,
})
}, [src])
//update (remove) state onUnMount
useEffect(() => {
return () => {
setState({
src: null,
errored: false,
})
}
}, [])
const onError = () => {
//1st error
if (!state.errored) {
setState({
src: fallbackSrc,
errored: true,
});
} else if (state.errored && state.src) {
//2nd error
//when error on fallbacksrc - remove src
setState({
src: null,
errored: true,
});
}
}
return (
state.src && <img
src={state.src}
onError={onError}
{...props}
/>
)
}
export default ImageFallback
用法...
<ImageFallback src={anySrc} fallbackSrc={anyFallbackSrc} className={classes.logo} alt='' />
答案 15 :(得分:0)
打字稿版本:
const Avatar = (): JSX.Element => {
function imageErrorHandler(e: React.SyntheticEvent<HTMLImageElement, Event>) {
const el = e.target as HTMLImageElement
el.onerror = null
el.src = '/fallback.png'
}
return <img src={'/smth.png'} onError={imageErrorHandler}/>
},
)
使用 forwardRef 和可能的 null src:
import { forwardRef } from 'react'
type Props = Omit<React.ComponentPropsWithoutRef<'img'>, 'src'> & { src?: null | string }
const Avatar = forwardRef<HTMLImageElement, Props>(
({ src, ...rest }, ref): JSX.Element => {
function imageErrorHandler(e: React.SyntheticEvent<HTMLImageElement, Event>) {
const el = e.target as HTMLImageElement
el.onerror = null
el.src = '/fallback.png'
}
return <img src={src || '/alternative.png'} onError={imageErrorHandler} ref={ref} {...rest} />
},
)
答案 16 :(得分:0)
尝试使用此自定义图片组件:
import React, { useRef } from 'react';
import PropTypes from 'prop-types';
import defaultErrorImage from 'assets/images/default-placeholder-image.png';
const Image = ({ src, alt, className, onErrorImage }) => {
const imageEl = useRef(null);
return (
<img
src={src}
alt={alt}
className={className}
onError={() => {
imageEl.current.src = onErrorImage;
}}
ref={imageEl}
/>
);
};
Image.defaultProps = {
onErrorImage: defaultErrorImage,
};
Image.propTypes = {
src: PropTypes.string.isRequired,
alt: PropTypes.string.isRequired,
className: PropTypes.string.isRequired,
onErrorImage: PropTypes.string,
};
export default Image;
答案 17 :(得分:0)
我使用 TypeScript 扩展了@Emils 解决方案并添加了
import * as React from "react";
type Props = {
src: string,
fallbackSrc: string,
placeholderColor?: string,
className?: string,
}
type State = {
src: string,
errored: boolean,
loaded: boolean
}
export default class Image extends React.Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = {
src: props.src,
errored: false,
loaded: false
};
}
onError = () => {
if (!this.state.errored) {
this.setState({
src: this.props.fallbackSrc,
errored: true,
});
}
}
onLoad = () => {
if(!this.state.loaded){
this.setState({loaded: true});
}
}
render() {
let style = {
backgroundColor: this.props?.placeholderColor || "white"
};
if(this.state.loaded){
style.backgroundColor = "transparent";
}
return (
<img
style={style}
onLoad={this.onLoad}
onError={this.onError}
{...this.props}
src={this.state.src}
/>
);
}
}
答案 18 :(得分:0)
对于 SSR(服务器端渲染)...
所以,这里有一个(对我来说)有效的解决方法!
const Img: FC<
DetailedHTMLProps<ImgHTMLAttributes<HTMLImageElement>, HTMLImageElement>
> = ({ src, ...props }): JSX.Element => {
const [hasRendered, setHasRendered] = useState(false);
const imgRef = useRef<HTMLImageElement | null>(null);
useEffect(() => {
if (imgRef.current && hasRendered) {
imgRef.current!.src = src || '';
}
}, [src, hasRendered]);
useEffect(() => {
setHasRendered(true);
}, []);
return (
<img
{...props}
ref={imgRef as any}
alt={props.alt || 'image'}
aria-hidden={true}
onError={...}
onLoad={...}
/>
);
};
所以,魔术发生在两个 useEffect
钩子中。 (仅使用一个不起作用)。
基本上,由于 useEffect
dep,第二个 hasRendered
确保第二次触发(或组件重新渲染)第一个钩子(在初始渲染之后),然后强制设置图像 src在那个钩子中,然后触发客户端上的事件!
答案 19 :(得分:0)
正如其中一条评论中提到的那样,最好的解决方案是使用react-image库。在构建后尝试提供静态版本的React网站时,使用 onError 将会失败。
这是一个超级简单明了的示例,该示例如何使用反应图像,只需导入Img组件
import {Img} from 'react-image'
然后再指定要尝试加载的src列表
<Img
src={['images/image1.svg', 'images/default.svg']}
alt="Some title"
/>
如果找不到第一个网址,则将加载第二个网址,还有其他一些很酷的功能,例如在加载图片时显示微调框,或在没有列出的图片可用的情况下显示其他组件
答案 20 :(得分:0)
以前的版本存在错误;他们不认为src
可以更改。因此,我制定了最终的解决方案:
src
时的支持情况onError
(意味着您可以像平时对onError
一样将ImageWithFallback
传递给<img />
)这里是:
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}
/>
);
},
);
答案 21 :(得分:0)
如果有人将图像src与require一起使用,则onError不能作为-
<img src={require(`./../../assets/images/${props.imgName}.png`)} className="card-img" alt={props.name} />
然后require引发错误,我尝试了多种方法,并试图以-
捕获块解决方案 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} />
答案 22 :(得分:0)
我这样写。
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);
答案 23 :(得分:0)
以下是使用钩子的答案:
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} ... /></>
答案 24 :(得分:0)
如果可以的话,您可以使用object
。像下面这样的东西会很好用
<object data={expected_image} type="image/jpg">
<img src={DEFAULT} alt="404" />
</object>
查看此答案以获取更多详细信息 https://stackoverflow.com/a/29111371/1334182
答案 25 :(得分:0)
我是怎么做到的。
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}/>;
}
}
答案 26 :(得分:-1)
这对我有用。
{<img className="images"
src={`/images/${student.src ? student.src : "noimage.png" }`} alt=
{student.firstname} />}
student是我的数组的名称,当没有图像显示时,图像为noimage。