Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

firstItem not working #63

Closed
dnish opened this issue May 5, 2017 · 16 comments
Closed

firstItem not working #63

dnish opened this issue May 5, 2017 · 16 comments

Comments

@dnish
Copy link

dnish commented May 5, 2017

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?

@bd-arc
Copy link
Contributor

bd-arc commented May 9, 2017

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?

@dnish
Copy link
Author

dnish commented May 9, 2017

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.

@bd-arc
Copy link
Contributor

bd-arc commented May 9, 2017

@dnish Thanks for the detailed info! I'll take a look at it as soon as possible.

@bd-arc
Copy link
Contributor

bd-arc commented Jun 5, 2017

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.

@PublicParadise
Copy link

PublicParadise commented Jun 5, 2017

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

@bd-arc
Copy link
Contributor

bd-arc commented Jun 7, 2017

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

@bd-arc
Copy link
Contributor

bd-arc commented Jul 21, 2017

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.

@bd-arc bd-arc closed this as completed Jul 21, 2017
@sitorush
Copy link

sitorush commented Nov 17, 2017

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.

@bd-arc
Copy link
Contributor

bd-arc commented Nov 17, 2017

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

@sitorush
Copy link

"react-native-snap-carousel": "^3.4.0",?

@bd-arc
Copy link
Contributor

bd-arc commented Nov 17, 2017

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

@juanamd
Copy link

juanamd commented Jan 15, 2018

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

@bd-arc
Copy link
Contributor

bd-arc commented Jan 15, 2018

@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 initialNumToRender by setting it to 30. Result: it works! This means that the issue is, as I feared, a FlatList one and that I have no control over this behavior. It seems like the FlatList component 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 useScrollView to true. Note that you will loose all FlatList optimizations by doing that.
  • Play with the following FlatList props until you find something that suits your needs: initialNumToRender, maxToRenderPerBatch, windowSize and updateCellsBatchingPeriod.
  • Pray that the Facebook team will, some day, fix all those ridiculous issues...

@balwinder4264
Copy link

 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 }) }
        />
    );
}

}

@Hegazy360
Copy link

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

@luiey
Copy link

luiey commented Oct 5, 2020

 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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants