リストの詳細ビューである反応コンポーネントがあります。
画像が存在せず、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;
完璧な答えはないので、使用しているスニペットを投稿しています。 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,
};
これは私に最適です
<img src={record.picture} onError={(e)=>{e.target.onerror = null; e.target.src="image_path_here"}}/>
非制御コンポーネントを使用できます:
<img src={this.state.img} ref={img => this.img = img} onError={
() => this.img.src = 'img/default.img'
}>
コンポーネントのrenderメソッドをトリガーし、最終的にコンポーネントがプレースホルダーで再レンダリングする状態を変更するよりも、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;
フォールバックイメージも失敗すると、アーサーの答えは無限のコールバックになります。
これを回避するには、最初に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';
}
}}
/>
同様の問題に遭遇し、私が見つけた最良の解決策は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
条件は無限ループを防ぐのに十分であるため(バックアップイメージもロードに失敗した場合)、必要ありません(実際には役に立たない)。
そう:
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; } }} />
);
}
@DepHの答えは素晴らしいですが、エラーソースも読み込まれない場合、無限ループを生成します。これにより、コールバックループを回避できました。
onError={(e)=>{ if (e.target.src !== "image_path_here")
{ e.target.onerror = null; e.target.src="image_path_here"; } }}
@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;
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
}}
/>
これは私が現在使用しているものです。
要素のスタイルを変更したり、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
}}
/>
それが役に立てば幸い!
要件に問題がなければ、object
を使用できます。以下のようなものは完全に正常に動作します
<object data={expected_image} type="image/jpg">
<img src={DEFAULT} alt="404" />
</object>
詳細については、この回答を確認してください https://stackoverflow.com/a/29111371/1334182
それが私がやった方法です。
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}/>;
}
}
フックを使用した答えは次のとおりです。
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
propの変更を処理する場合は、key
のsrc
propを渡すことができます。 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='...' />
このようなキーの使用が失敗する可能性のある極端な不自然なEdgeのケースは、兄弟コンポーネントの場合です。同じキーを持っている場合、1つの兄弟ノードのみがレンダリングされると思います。これを回避するには、おそらく<>
Fragment
。
<><Image key={srcProp} ... /></>
<><Image key={srcProp} ... /></>
このように書きました。
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);