It's a questiob but may turn out to be a bug.
Problem: _renderItems gets called thrice
How to replicate:
Following is the code to display a carousel in a very simple example:
import React, {PureComponent} from 'react'
import { ScrollView, Text, View, SafeAreaView,Platform, Dimensions, StyleSheet } from 'react-native';
import Carousel from 'react-native-snap-carousel';
export default class SnapDemo extends PureComponent {
constructor(props){
super(props)
this.state = {data: [{'num':1},{'num':2},{'num':3}]}
}
_renderItem (item) {
console.log(item)
return(<View key={item.item.num} style={{backgroundColor:'orange', height:100}}><Text>{item.item.num}</Text></View>)
}
render(){
return(
<SafeAreaView style={{height: 600}}>
<Carousel
data={this.state.data}
renderItem={this._renderItem}
itemWidth={Dimensions.get('window').width * 0.85}
sliderWidth={Dimensions.get('window').width}
containerCustomStyle={{flex:1}}
removeClippedSubviews={true}
keyExtractor={(item, index) => index.toString()}
slideStyle={{ flex: 1 }}/>
</SafeAreaView>
)
}
}
There are 2 problems:
I have experienced this behavior as well. Here is a snack that reproduces this issue with static data.
@deepakaggarwal7 @kdrich Does the problem still occur if you simply replace Carousel with FlatList (the required props are the same) and add horizontal={true}?
Don't forget the following:
import { FlatList } from 'react-native';.
@deepakaggarwal7 @kdrich Does the problem still occur if you simply replace
CarouselwithFlatList(the required props are the same) and addhorizontal={true}?Don't forget the following:
import { FlatList } from 'react-native';.
RenderItem with a FlatList gets called once only for every iterated item.
Same issue
Ran into this issue as well. The fix is to make your key extractor more unique by combine your item key with the index. So something like keyExtractor={(item, index) => item.id+"_"+index}
@ethantran, it does look like keyExtractor is passed through to the Carousel component, though I don't see any change in behavior adding a more specific keyExtractor similar to what you reference above.
You can see an example here
The logs cumulate the total number of times each item is rendered. It is still three.
I see. The keyExtractor fixed problem 2, the warning message, for me. I am not sure how to fix the multi-render except using a pure component. Example
I have a similar problem. The renderItem gets triggered multiple times for the same index. It also triggers the renderItem with index 0 up to four times - no idea why this is happening
<Carousel
lockScrollWhileSnapping
ref={(c) => {
this.carousel = c;
}}
windowSize={1}
initialNumToRender={1}
maxToRenderPerBatch={1}
data={this.props.articles}
sliderWidth={this.props.screenWidth}
itemWidth={this.props.screenWidth}
itemHeight={this.props.screenHeight}
keyExtractor={(item, index) => item.article+ '-' + index}
scrollEnabled={this.isListMode() && this.state.isArticleLoaded}
onSnapToItem={this.onItemSnap}
renderItem={(params) => renderCorrectArticleDetail(params)}
/>
Even with initialNumToRender={1} and maxToRenderPerBatch={1} it still triggers renderItem 12 times. This is causing big performance issues for me. Any ideas?
Any progress here? I get the same problem. renderItem calls 10+ time
any update here?
same problem here.
hint to get rid out of this issue
use index value from the item.
change
{item, index} => index === 0
to
{item} => item.index === 0
Any idea how to solve this ? @seniordev32 solution doesn't work
For me, works with theses steps:
${item.id};<Carousel
keyExtractor={_keyExtractor}
/>
For API request, you must use:
useEffect(() => {
// Using an IIFE
(async function getRecords() {
const response = await callToAPI();
setRecords(response.data);
})();
}, []);Any update on this issues ?
I have a similar problem. The renderItem gets triggered multiple times for the same index. It also triggers the renderItem with index 0 up to four times - no idea why this is happening
<Carousel
lockScrollWhileSnapping
ref={(c) => {
this.carousel = c;
}}
windowSize={1}
initialNumToRender={1}
maxToRenderPerBatch={1}
data={this.props.articles}
sliderWidth={this.props.screenWidth}
itemWidth={this.props.screenWidth}
itemHeight={this.props.screenHeight}
keyExtractor={(item, index) => item.article+ '-' + index}
scrollEnabled={this.isListMode() && this.state.isArticleLoaded}
onSnapToItem={this.onItemSnap}
renderItem={(params) => renderCorrectArticleDetail(params)}
/>Even with initialNumToRender={1} and maxToRenderPerBatch={1} it still triggers renderItem 12 times. This is causing big performance issues for me. Any ideas?
Are you changing state in renderItem?
I'm changing state in onSnapToItem (to save the current item) but this rerenders the carousel which in turn jumps back to the index specified in firstItem. Any solution to this?
Couple of points:
Update your _renderItem() function so that it is returning a component (EG Move the returned View + Text to its own list-item component and pass details through props). This allows you to implement shouldComponentUpdate() lifecycle event in list-item to ensure that re-renders only happen when required. You may still see _renderItem() being called, but the render function in list-item component will not be re-rendered if shouldComponentUpdate() is configured correctly.
keyExtractor uses an anonymous function in render(), move this logic to outside of the render function (EG keyExtractor={this._keyExtractor})
Any update on this issues ?
Same issue, any solution ?
Same issue, any solution ?
Try using a pure component. Here is a barebones example, you can abstract the pure component to it's own file
```
const carouselComponent = (props) => {
const [selected, setSelected] = useState(null);
const [data, setData] = useState(props.data);
// THIS IS THE PURE PART
const Item = ({ item, onPress, style }) => (
<TouchableOpacity
key={item.id}
onPress={onPress}
style={[styles.itemStyle, style]}
>
<View style={styles.item}>
<Text style={styles.name}>
{item.name}
</Text>
<Image
style={styles.image}
source={{
uri: item.image,
}}
/>
</View>
</TouchableOpacity>
);
// END OF PURE
// RENDER ITEM
const renderItem = ({ item }) => {
const selectedStyle = item.id === selectedId ? SELECTED : NONSELECTED;
return (
<Item
item={item}
onPress={() => handlePress(item)}
style={{ selectedStyle }}
/>
);
};
return(
<View>
<Carousel
ref={myCarousel}
data={data}
renderItem={renderItem}
keyExtractor={(item) => item.id}
extraData={selectedId}
removeClippedSubviews={true}
/>
<View>
)
// const styles =...
}```
@ebarahona Yes, my item is a PureComponent, but the render is call many
Most helpful comment
I have a similar problem. The renderItem gets triggered multiple times for the same index. It also triggers the renderItem with index 0 up to four times - no idea why this is happening
<CarousellockScrollWhileSnappingref={(c) => {this.carousel = c;}}windowSize={1}initialNumToRender={1}maxToRenderPerBatch={1}data={this.props.articles}sliderWidth={this.props.screenWidth}itemWidth={this.props.screenWidth}itemHeight={this.props.screenHeight}keyExtractor={(item, index) => item.article+ '-' + index}scrollEnabled={this.isListMode() && this.state.isArticleLoaded}onSnapToItem={this.onItemSnap}renderItem={(params) => renderCorrectArticleDetail(params)}/>Even with initialNumToRender={1} and maxToRenderPerBatch={1} it still triggers renderItem 12 times. This is causing big performance issues for me. Any ideas?