react-native-snap-carousel takes a lot of time to render photos - react-native

I am using a react-native-snap-carousel to render a photo gallery. I noticed that first entrance to the gallery takes a lot of time to render photos, especially if there are several photos.
const renderItem = ( photo) => {
console.log(photo); //<- it shows up quickly in the console, but the photo is not visible for a long time
return (
<View style={styles.imgContainer}>
<Image source={{ uri: photo.item.uri }} style={styles.img} />
</View>
)};
return (<Carousel
ref={carouselRef}
data={props.photos}
renderItem={renderItem}
sliderWidth={sliderWidth}
itemWidth={itemWidth}
activeSlideAlignment={'center'}
onSnapToItem={index => setActiveSlide(index)}
/>)
What could be the reason for this behavior?
What can I do with this?

Related

Large amount of data affecting performance

I have a huge list of data that I want to send to a different screen when I am transitioning, but the problem I am experiencing is a performance issue. Like when I transition, the response time takes about 2-3 seconds for it to transfer and it's not very responsive.
Here's my code setup of what I have:
const PopularNow = (props) => {
return (
<FlatList
data={props.data}
keyExtractor={item => item.id.toString()} //id.toString()
horizontal
showsHorizontalScrollIndicator={false}
style={{paddingLeft: 10}}
ItemSeparatorComponent={() => <ItemSeparator width={20} />}
ListHeaderComponent={() => <ItemSeparator width={20} />}
ListFooterComponent={() => <ItemSeparator width={50} />}
renderItem={({item}) => {
if (item.cover.image_id) {
return (
<TouchableOpacity
activeOpacity={0.7}
onPress={() =>
props.navigation.push('GamePreview', {
gameName: item.name,
gameCover: item.cover.image_id,
gameReleased: item.first_release_date,
total_Rating: item.total_rating,
gamePlatforms: item.platforms,
gameSummary: item.summary,
similarGames: item.similar_games,
Screenshot: item.screenshots,
Videos: item.videos,
====> involveCompanies: item.involved_companies,
gameGenres: item.genres,
artworks: item.artworks,
age_Rating: item.age_ratings,
age_Rating_Description: item.age_ratings,
gameModes: item.game_modes,
multiplayerModes: item.multiplayer_modes,
playerPerspectives: item.player_perspectives,
gameEngine: item.game_engines,
gameSeries: item.collection,
gameDLC: item.dlcs,
})
}>
<Image
resizeMode="cover"
style={styles.containerGames}
source={{uri: getImage(item.cover.image_id)}}
/>
</TouchableOpacity>
);
}
}}
/>
}
)
the involved_companies is what makes the screen transition very slow because of the amount of companies I invoke from the api. When I comment this out the performance is very responsive. I want to know if there is an alternative to improve performance with a large amount of data.
I would suggest not to pass the whole data to the next screen. The listing should only display what it's need to be display (based on your design).
All you need is just to pass the id, so in the GamePreview screen will have to call another API to get game preview detail.
By doing this, you GamePreview screen is deeplink-able because you may allow user to share the game preview detail link. If using current way, your link have to contains all the params and which is not possible because some property is object.
It should work when reduce amount of unnecessary data. If it's still doesn't work for your case, you can try this awesome library flash-list

React native List footer component not rendering(funtion component)

I am trying to achieve pagination for infinite scrolling in react native. When loading, I want to render the loading spinner at the bottom of the Flat list component. (Note: I'm using Expo for this app)
const renderFooter = () => {
if (!category.loading) return null;
return (
<View style={spinnerStyles.container}>
<ActivityIndicator animating size="large" color="#0000ff" />
</View>
);
};
return (
<View style={styles.container}>
<FlatList
columnWrapperStyle={{ justifyContent: "space-between" }}
numColumns={2}
data={category.data}
renderItem={categoryItem}
keyExtractor={(item) => item._id + item.sub_category}
onEndReachedThreshold={0}
listFooterComponent={renderFooter}
onEndReached={() => loadMore()}
/>
</View>
);
The loading spinner not correctly working with the flat list footer.
Has anyone run into this issue before, or does anyone have a solution?
Sorry, it's my simple syntax error. It's actually ListFooterComponent not listFooterComponent. Now it's working fine, Thank you.
Instead of calling the refrence, call the function. It should look something like this.
ListFooterComponent={renderFooter()}

Autoplay video on element focus in react-native

import {Video} from 'expo-av';
return (
<FlatList
data={videos}
// keyExtractor={(item,ind}
keyExtractor={(item) => item.names}
renderItem={({item})=>(
<TouchableOpacity
onPress={() => {console.log('pushed');navigation.push('Details',{url:item.videourl})}}>
<Video
usePoster="true"
source={{ uri: item.videourl }}
rate={1.0}
volume={1.0}
isMuted={false}
resizeMode="cover"
shouldPlay={isFocused ? true : false}
// isLooping
// useNativeControls
posterSource={{uri:item.imageurl}}
style={{ height: 300 }}
/>
</TouchableOpacity>
)}/>
);
If one video gets focused then the video must be played and if the video is not focused then it should pause.I am using expo-av for playing video. The above code is playing all videos on the screen but I want to play the video which is focused just like what youtube does.
To do this you need to keep track of how the scrollview has moved (the offset). FlatList has an onScroll property, where the callback is given information about the list layout etc., and you are interested in tracking how much the content has been scrolled vertically - that is contentOffset.y.
Dividing this value by the list item height (a constant 300 in your case) and rounding will give you the index of the item that should be playing.
Use state to store the currently focused index:
const [focusedIndex, setFocusedIndex] = React.useState(0);
Add a handler for the onScroll event :
const handleScroll = React.useCallback(({ nativeEvent: { contentOffset: { y } } }: NativeSyntheticEvent<NativeScrollEvent>) => {
const offset = Math.round(y / ITEM_HEIGHT);
setFocusedIndex(offset)
}, [setFocusedIndex]);
Pass the handler to your list:
<FlatList
onScroll={handleScroll}
...
/>
and modify the video's shouldPlay prop:
<Video
shouldPlay={focusedIndex === index}
...
/>
You can see a working snack here: https://snack.expo.io/#mlisik/video-autoplay-in-a-list, but note that the onScroll doesn't seem to be called if you view the web version.
Try https://github.com/SvanBoxel/visibility-sensor-react-native
Saved my time. You can use it like.
import VisibilitySensor from '#svanboxel/visibility-sensor-react-native'
const Example = props => {
const handleImageVisibility = visible = {
// handle visibility change
}
render() {
return (
<View style={styles.container}>
<VisibilitySensor onChange={handleImageVisibility}>
<Image
style={styles.image}
source={require("../assets/placeholder.png")}
/>
</VisibilitySensor>
</View>
)
}
}

ReactNative ScrollToIndex too slow

im using react native to create an app for a legal document. i need the document to be scrollable. i rendered it using VirtualizedList.
thing is when i try to use scrollToIndex(index: 'something') performance is too slow.
my list contains about 4000 rendered items (each being about a paragraph long).
is there any way to make this run smoother?
export default function App() {
const scroller = useRef();
return (
<SafeAreaView>
<View style={styles.upperContainer}>
<CustomButton
onPress={() => {
scroller.current.scrollToIndex({ index: 1547 });
}}
/>
</View>
<View style={styles.flatContainer}>
<VirtualizedList
ref={scroller}
data={data}
renderItem={({ item }) => (
<CustomText data={item.content} type={item.type} />
)}
getItem={(data, index) => data[index]}
getItemCount={(data) => data.length}
keyExtractor={(item) => item.number.toString()}
initialNumToRender={4000}
onScrollToIndexFailed={() => {
alert('error');
}}
/>
</View>
</SafeAreaView>
);
}
This question is similar to these ones and maybe you can reference some of the answers and see what works for your case. Basically, you need a pure component to make this work.
Link - Flatlist performance slow
Link - VirtualizedList: You have a large list that is slow to update

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...