React Native local image loads a second after content - react-native

I have a local image that I am using as a background image. It loads around a second after the rest of the content.
<Image source={require('./assets/climbing_mountain.jpeg')} style={styles.imageContainer}>
imageContainer: {
flex: 1,
width: null,
height: null,
}
Is there a way to load the content after the image is loaded? I tried using the onLoad and onLoadEnd props, but they were fired prior to the image loading.

Yes there is.. it's not that simple actually, you will need to use Image prefetch.. check this link : React Image prefetch
Or actually you can try this:
<Image
onLoadEnd={()=>this.setState({loadEnd:true})}
source={require('./assets/climbing_mountain.jpeg')}
style={styles.imageContainer}>
and in the render method you can do something like which I don't really recommend:
render(){
if(!this.state.loadEnd) {
return(
<Image
key='image_key'
onLoadEnd={()=>this.setState({loadEnd:true})}
source={require('./assets/climbing_mountain.jpeg')}
style={styles.imageContainer}>
)
}else {
return (
<View>
....
<Image
key='image_key'
onLoadEnd={()=>this.setState({loadEnd:true})}
source={require('./assets/climbing_mountain.jpeg')}
style={styles.imageContainer}>
</view>
....
)
}
}

Related

Can't display Image with temporary file from react native vision camera

I'm learning React Native by building an app that takes a picture and shows the image in a gallery.
I'm using react-native-vision to take the photo and react-native-fs to access the temporary file as suggested in this answer and use it as the uri of <Image/>
However, the View that should display a list of </Image> it's showing a blank space
This is my code:
// saves photo on Array and closes the Camera View
const onPressButton = async () => {
console.log(cameraRef.current);
console.log(123);
const photo = await cameraRef.current.takePhoto({
flash: 'off',
qualityPrioritization: 'speed',
});
console.log(photo);
setPhotos([...photos, photo]);
setShowCamera(false);
return;
};
// how I'm trying to render the photos
{photos && photos.length > 0 && (
<View style={{width: '50%', height: '50%'}}>
{photos.map((photo, index) => (
<View key={index}>
{console.log('file://' + DocumentDirectoryPath + photo.path)}
<Image style={{maxWidth: 10, maxHeight: 20}} source={{uri: 'file://' + DocumentDirectoryPath + photo.path}} />
</View>
))}
</View>
)}
This is how it looks:
Is there something wrong with my code?
Thanks for the help.
There are 2 potential errors in your source code.
Photo taken by react-native-vision is chached. (photo.path look something like this: /data/user/0/your.app/cache/mrousavy6472....jpg) So do not use DocumentDirectoryPath, use just source={{uri: 'file://' + photo.path}}
Second potential error is Your photo is not shown because he is hidden from view. Try to set style like this: style={{width: '100%', height: '100%'}}
So in final look like this:
<Image style={{width: '100%', height: '100%'}} source={{uri: 'file://' + photo.path}} />

React Native - Performance drop to 10 fps when rendering an image inside a SectionList

I have SectionLists inside a horizontal FlatList (react-native-snap-carousel). Each SectionList item represents an entry in a timeline. Some of the items are just text and others also have an image.
While scrolling, every time an image is visible on the screen, the fps drop to less than 10. If I simply comment the <Image> tag so that no image is rendered, the fps go up to 50>fps.
The app on the left has images, the app on the right has <Image /> component commented.
I only tested the app on Android.
Any explanation why the fps drop when an image is displayed?
renderItem:
render() {
const {
containerStyle,
hourStyle,
hourTextStyle,
contentStyle,
iconDashesStyle,
titleText,
descriptionText,
notesText
} = styles;
const activity = this.props.item;
const { type, category, date, note } = activity;
return (
<View style={containerStyle}>
<View style={hourStyle} >
<Text style={hourTextStyle}>
{moment(date).format('HH:mm')}
</Text>
</View>
<View style={iconDashesStyle}>
{this.renderIcons()}
{this.renderDashes()}
</View>
<View style={contentStyle}>
<Text style={titleText}>{getActivityName(type, category).toUpperCase()}</Text>
<Text style={descriptionText}>{getActivityDescription(activity)}</Text>
<Text style={notesText}>{note}</Text>
{this.renderImage()}
</View>
</View>
);
}
renderImage function:
renderImage() {
const { type } = this.props.item;
if (type === ID_SHARE_MOMENT && this.props.image) {
const { uri, ratio } = this.props.image;
return (
<View
ref={r => (this.imgRef = r)}
style={[styles.momentImgContainer, { aspectRatio: ratio }]}
collapsable={false}
>
<TouchableOpacity onPress={this.onPressImage}>
<Image
style={styles.momentImg}
source={{ uri }}
resizeMode='cover'
/>
</TouchableOpacity>
</View>
);
}
}
The second app without images has the renderImage as follows:
<TouchableOpacity onPress={this.onPressImage}>
{ /*
<Image
style={styles.momentImg}
source={{ uri }}
resizeMode='cover'
/>
*/ }
</TouchableOpacity>
Edit 1
While trying to improve the performance of my app, I followed this link of Adam Stanford on medium, which suggested to load static assets directly from the app package (images included via Xcode asset catalogs or in the Android drawable folder).
I started with the background image of the entry screen that precedes the screen shown above, which only has a background image, a logo, and a spinner:
Only by doing this in this first image, look what happened:
The fps went up to 40+ even when rendering the images in the timeline. However, I do not understand the relation...

ImageBackground doesn't accept ResizeMode

Anyone here can help me make resizeMode work with <ImageBackground>?
It gives an error that resizeMode is applied to View, which apparently doesn't support it.
But i need to find a workaround, as i find pretty complicated to use <Image /> as a background for a block with info.
Thanks in advance!
<ImageBackground
style={[styles.image]}
source={{ uri: url }}
imageStyle={{resizeMode: 'contain'}}
>
// other components here
</ImageBackground>
Hope it helps!
NOTE: At the time I wrote this, <ImageBackground /> was an undocumented feature not yet released. But it does exist now.
There is no <ImageBackground /> that I'm aware of, but you can create one.
If you're trying to set an image as the background to some text, then <Image /> is the best way. Where do you feel it's overly complicated? Something like this should work...
class BackgroundImage extends Component {
render() {
return (
<Image
source={this.props.src}
style={styles.backgroundImage}>
{this.props.children}
</Image>
)
}
}
const styles = StyleSheet.create({
backgroundImage: {
flex: 1,
width: null,
height: null,
resizeMode: 'cover'
}
});
Then you'd use it like this...
<BackgroundImage
src={require('./background.jpg')}>
<Text>Your Content Goes Here!</Text>
</BackgroundImage>

onLayout with Image - React Native

I have a problem with onLayout in Image:
I have a function to display the dimension.
measureView(event) {
console.log(event.nativeEvent.layout.width);
console.log(event.nativeEvent.layout.height);
}
This Works and shows me the dimension of the TouchableWithoutFeedback
<TouchableWithoutFeedback
style={styles.touchableWithoutFeedback}
onLayout={(event) => this.measureView(event)}>
<Image style={styles.image}
source={require("./../assets/images/photo_1.jpg")}/>
</TouchableWithoutFeedback>
But With the onLayout in the Image, i got nothing, just undefined.
<TouchableWithoutFeedback
style={styles.touchableWithoutFeedback}>
<Image style={styles.image}
source={require("./../assets/images/photo_1.jpg")}
onLayout={(event) => this.measureView(event)}/>
</TouchableWithoutFeedback>
Do you have an Idea why?
Thanks!
I had this problem recently as well. It looks like the <Image /> component mounts before the actual image gets loaded into the container. You probably want to instead use the onLoad property of <Image />. Once you do that you can pretty much proceed as normal...
<Image
onLoad={event => { console.log(event.nativeEvent.source); }}
source={require("./../assets/images/photo_1.jpg")}
style={styles.image}
/>
// Would log { height: 123, url: 'somestring', width: 123 }
Keep in mind that may or may not only work for static resources. I'm not 100% that network images provide a size through that function.
Good luck! :)

Full Screen Background Image behaves differently from network and local storage

I am trying to stretch a background-image to full screen.
Images seem to behave differently when fetched from Network and from Local storage.
This function does not stretch the image as requested (there is a white margin of around 70 pixels from the right):
This is my render() fundtion:
var BackgroundImage = require('./images/logo_og.png');
render(){
return(
<View style={[{flex: 1, alignItems: 'stretch'}]}>
<Image source={BackgroundImage} style={[{flex: 1}]} >
</Image>
</View>
);
The same render function works well displaying the image being fetched from the network:
render(){
return(
<View style={[{flex: 1, alignItems: 'stretch'}]}>
<Image source={{uri:'https://facebook.github.io/react/img/logo_og.png'}} style={[{flex: 1}]} >
</Image>
</View>
);
any idea what is going on?
Similar issue was reported here. Try setting the Image's width to null:
<Image source={BackgroundImage} style={[{flex: 1, width: null}]} >