Reputation: 6359
Is it possible to load a local image if the remote image failed?
For example, I have the following code:
<Image style={ styles.userImage }
source={ { uri: http://example.com/my_image.jpg } }
onError={(error) => ...}
/>
In case for example I don't have the rights to access http://example.com/my_image.jpg
, I'll get an error in onError
. Is there a way then to load a local image instead?
Upvotes: 23
Views: 25820
Reputation: 677
Create a component ImageLoad like this:
import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
import { Image, ImageBackground, ActivityIndicator, View } from 'react-native';
class ImageLoad extends PureComponent {
static propTypes = {
isShowActivity: PropTypes.bool,
};
static defaultProps = {
isShowActivity: true,
};
constructor(props) {
super(props);
this.state = {
isLoaded: false,
isError: false
};
}
onLoadEnd(){
this.setState({
isLoaded: true
});
}
onError(){
this.setState({
isError: true
});
}
render() {
const {
style, source, resizeMode, borderRadius, backgroundColor, children,
loadingStyle, placeholderSource, placeholderStyle,
customImagePlaceholderDefaultStyle
} = this.props;
return(
<ImageBackground
onLoadEnd={this.onLoadEnd.bind(this)}
onError={this.onError.bind(this)}
style={[styles.backgroundImage, style]}
source={source}
resizeMode={resizeMode}
borderRadius={borderRadius}
>
{
(this.state.isLoaded && !this.state.isError) ? children :
<View
style={[styles.viewImageStyles, { borderRadius: borderRadius }, backgroundColor ? { backgroundColor: backgroundColor } : {}]}
>
{
(this.props.isShowActivity && !this.state.isError) &&
<ActivityIndicator
style={styles.activityIndicator}
size={loadingStyle ? loadingStyle.size : 'small'}
color={loadingStyle ? loadingStyle.color : 'gray'}
/>
}
<Image
style={placeholderStyle ? placeholderStyle : [styles.imagePlaceholderStyles, customImagePlaceholderDefaultStyle]}
source={placeholderSource ? placeholderSource : require('./Images/empty-image.png')}
>
</Image>
</View>
}
{
this.props.children &&
<View style={styles.viewChildrenStyles}>
{
this.props.children
}
</View>
}
</ImageBackground>
);
}
}
const styles = {
backgroundImage: {
position: 'relative',
},
activityIndicator: {
position: 'absolute',
margin: 'auto',
zIndex: 9,
},
viewImageStyles: {
flex: 1,
backgroundColor: '#e9eef1',
justifyContent: 'center',
alignItems: 'center'
},
imagePlaceholderStyles: {
width: 100,
height: 100,
resizeMode: 'contain',
justifyContent: 'center',
alignItems: 'center'
},
viewChildrenStyles: {
top: 0,
left: 0,
right: 0,
bottom: 0,
position: 'absolute',
backgroundColor: 'transparent'
}
}
export default ImageLoad;
and use this anywhere in your app:
<ImageLoad
style={{ width: 320, height: 250 }}
loadingStyle={{ size: 'large', color: 'blue' }}
source={{ uri: 'url image' }}
/>
Upvotes: 0
Reputation: 1662
To elaborate on Cherniv's answer you could create an <Images />
component that abstracts this away for you:
import React from 'react';
import { Image } from 'react-native';
export default class Images extends React.Component {
static defaultProps = {
source: [],
onError: () => {},
}
state = { current: 0 }
onError = error => {
this.props.onError(error);
const next = this.state.current + 1;
if (next < this.props.source.length) {
this.setState({ current: next });
}
}
render() {
const { onError, source, ...rest } = this.props;
return (
<Image
source={source[this.state.current]}
onError={this.onError}
{...rest}
/>
);
}
}
Then you can use it like this:
import Images from './Images';
<Images
source={[
{ uri: 'http://example.com/bad_image.jpg' },
{ uri: 'http://example.com/good_image.jpg' },
require('./default.jpg'),
]}
style={{
backgroundColor: '#ccc',
height: 200,
width: 200,
}}
/>
Upvotes: 5
Reputation: 1377
As per the latest docs you can use defaultSource
property. It shows the image till the original image loads, if the load fails the default image is shown Link to docs
Upvotes: 34
Reputation: 42176
Use component' state. In your constructor set initial url:
this.state = { image: { uri: 'http://example.com/my_image.jpg' } }
Create onError
handler:
onError(error){
this.setState({ image: require('your_local_image.path')})
}
And then combine it all together:
<Image style={ styles.userImage }
source={ this.state.image }
onError={ this.onError.bind(this) }
/>
Upvotes: 32