Hey,
I'm having an issue with setting firstItem. Most of the time, the wrong item is selected. We are using a function which returns the children, so we got something like this:
<Carousel
ref={'covers'}
sliderWidth={viewportWidth}
itemWidth={240}
inactiveSlideScale={0.9}
inactiveSlideOpacity={0.6}
showsHorizontalScrollIndicator={false}
snapOnAndroid={true}
removeClippedSubviews={false}
onSnapToItem={this.onSnap}
firstItem={8}
>
{this.getCovers()}
</Carousel>
In our case, the 8th item wasn't selected when the component mounts. If we do something like this:
componentDidMount() {
setTimeout(() => { this.refs.covers.snapToItem(8,false); },500);
}
...the correct item is selected. Are there any issues when generating the childrens via function?
Hey @dnish,
You shouldn't have any issue when returning children from a custom method (in fact, that's the way we're doing it). Still, there might be a problem if your children are generated asynchronously. This is supposed to be handled, but you might have uncovered some dirt :)
Could you share your method getCovers() so I can try to reproduce your issue? Could you also try this workaround and let me know if that works for you?
Hey,
our childrens are generated synchronously.
This is our getCovers method:
getCovers() {
return _.map(Playlist.getUserFiles(PlayerStore.playlist),(doc) => <Image style={styles.cover} key={doc._id} source={(doc.formattedCover) ? doc.formattedCover : require('app/images/no_cover.jpg')}/>);
}
The getUserFiles method:
Playlist.getUserFiles = function(playlistDoc) {
const ids = _.map(playlistDoc.userFiles,"id");
return _.filter(_.map(ids,(id) => _.find(CollectionsStore.userFiles,{_id:id})),(userFile) => userFile);
};
So all data is available during the render process.
If I add a console.log within my render method, I get correct values:
console.log(this.getCovers());
console.log(parseInt(PlayerStore.currentIndex));
Gives me 10 objects with the correct selected index (f.e. 9). But if 9 is selected, the cover of 8 is shown. If I select 8 or 7, it also shows the cover of 8.
I've also tried this approach, but still get the same error:
{(() => {
if(this.getCovers().length >= 10) {
return <Carousel
ref={'covers'}
sliderWidth={viewportWidth}
itemWidth={240}
inactiveSlideScale={0.9}
inactiveSlideOpacity={0.6}
showsHorizontalScrollIndicator={false}
snapOnAndroid={true}
removeClippedSubviews={false}
onSnapToItem={this.onSnap}
firstItem={parseInt(PlayerStore.currentIndex)}
>
{this.getCovers()}
</Carousel>;
}
})()}
Same problem also if I set a fixed value for firstItem:
firstItem={9}
8 is selected instead the last one 9.
@dnish Thanks for the detailed info! I'll take a look at it as soon as possible.
Hi @dnish,
I'm desperately trying to reproduce the issue you are facing, but to no avail so far. I've made a short screencast to show you that everything works fine for me: https://media.giphy.com/media/3o7bufKXOwspGnnbpe/giphy.gif
I initialize my Carousel with firstItem={2} and, as you can see, the third item is the one that's shown after init.
If you could set up a test case, I would gladly take a look at it.
@bd-arc I can easily reproduce this problem using this setup:
const firstItem = 2;
...
<Carousel
sliderWidth={sliderWidth}
itemWidth={itemWidth}
firstItem={firstItem}
inactiveSlideScale={0.94}
inactiveSlideOpacity={0.6}
enableMomentum={false}
containerCustomStyle={sliderEntryStyles.slider}
contentContainerCustomStyle={sliderEntryStyles.sliderContainer}
showsHorizontalScrollIndicator={false}
snapOnAndroid={true}
removeClippedSubviews={false}
onSnapToItem={(slideIndex: number) => this._centerMapOnMarker(slideIndex, places)}
>
{_getSlides(selectedPlace, places)}
</Carousel>
@PublicParadise Would you mind setting up a simple example project? Because I'm not able to reproduce the bug with only the code you've shared.
Since it works properly for me, I guess this has to do with how slides are generated...
Closing as no further feedback was provided.
Please note that version 2.4.0 fixes an issue that prevented firstItem to be updated dynamically. This might help.
I just had similar issue where the carousel has long list (eg. 90 items) and set the firstItem into high number will always select the 12th item. It turns out I have to add getItemLayout in order for FlatList to figure out how long the list will be.
<Carousel
...
getItemLayout={(data, index) => ({offset: viewportWidth * index, length: viewportWidth, index})}
...
/>
I hope this helps someone else related to firstItem issue.
@sitorush Which version of the plugin are you using?
Because, as you can see there, getItemLayout is now always overridden (see #193 for more information).
"react-native-snap-carousel": "^3.4.0",?
@sitorush Well then getItemLayout is not supposed to do anything :-)
If you take a look at #193, you'll see that you're not supposed to be facing the issue anymore. Let's continue the discussion there if need be.
FirstItem prop not working for me if the index is greater than ~6. Could only get it to work by enabling the "useScrollView" prop, or by having "initialNumToRender" to be the same as the index + 1. Of course, using this has a great performance penalty. Is there a way for this to work correctly at the moment?
Using version 3.5.0 with RN 0.52
@juanamd Unfortunately, this is definitely a FlatList bug, which is confirmed by the fact that everything works properly when setting useScrollView to true.
I'll copy-paste my comment to a similar issue as this might still help you.
I've just had an idea and tried overriding the default
initialNumToRenderby setting it to30. Result: it works! This means that the issue is, as I feared, aFlatListone and that I have no control over this behavior. It seems like theFlatListcomponent is not able to properly keep track of the items that are not in the currently rendered batch...I see three options at this point:
- Set
useScrollViewtotrue. Note that you will loose allFlatListoptimizations by doing that.- Play with the following
FlatListprops until you find something that suits your needs:initialNumToRender,maxToRenderPerBatch,windowSizeandupdateCellsBatchingPeriod.- Pray that the Facebook team will, some day, fix all those ridiculous issues...
I had same problem i add initialNumToRender={100} so Carousel working fine for first . 100 items
<Carousel
ref={(c) => { this._carousel = c; }}
initialNumToRender={100}
data={this.state.picture}
firstItem={this.state.index}
renderItem={this._renderItem}
sliderWidth={500}
itemWidth={500}
//onSnapToItem={(index) => this.setState({ activeSlide: index }) }
/>
);
}
}
Thanks @balwinder4264 I used your solution with a slight tweak, I set initialNumToRender={this.state.picture.length}, in my case I sometimes had a list with only a few items, other times I had a long list
I had same problem i add initialNumToRender={100} so Carousel working fine for first . 100 items <Carousel ref={(c) => { this._carousel = c; }} initialNumToRender={100} data={this.state.picture} firstItem={this.state.index} renderItem={this._renderItem} sliderWidth={500} itemWidth={500} //onSnapToItem={(index) => this.setState({ activeSlide: index }) } /> ); }}
I'm wondering why firstItem after some index is not showing related index data from array. I use your way which adding initial number to array length. Solving my firstItem thought
Most helpful comment
}