react-native-swiper-flatlist
react-native-swiper-flatlist copied to clipboard
onChangeIndex() doesn't always fire when using swipe feature
Description
- When user manually swipes item to side numerous times,
onChangeIndexcallback occasionally is not fired. - I have stripped back the props I was passing to
<SwiperFlatList>to the bare minimum (see code example below) and issue still seen. - Issue only seen with manual swipe
Info
- Issue seen on Android + iOS
- RN Version:
0.63.4(also seen inv0.62.2) react-native-swiper-flatlistversion:3.0.14(also seen inv3.0.8)
Code Example:
const LIST_ITEMS = [
{ title: 'Title 1 },
{ title: 'Title 2' },
{ title: 'Title 3' },
{ title: 'Title 4' },
];
export default class SwipeView extends Component {
constructor(props) {
super(props);
}
onChangeIndex({ index, prevIndex }) {
console.log('New Index: ' + index);
}
renderItem = ({ item }) => {
return <SwipeListItem item={item} />;
};
render() {
return (
<SwiperFlatList
autoplay={false}
data={LIST_ITEMS}
renderItem={this.renderItem}
showPagination={false}
onChangeIndex={this.onChangeIndex.bind(this)}
/>
)
}
}
Steps to recreate
- Render list with 4 items
- Swipe forward to index 1
- Swipe back to index 0
- Repeat swiping between index 0 & 1 many times
- onChangeIndex callback not always fired
I have found a work-around by also implementing onMomentumScrollEnd callback. Leaving this issue open incase you want to track the onChangeIndex issue.
Done a bit of digging into onChangeIndex issue and it looks like _onChangeIndex() in SwiperFlatList.tsx (line 77) receives the same value for _index and _prevIndex and this causes the onChangeIndex callback not to fire.
From a quick look, it seems like _onViewableItemsChanged() (line 181) is not setting the index on the swipe previous to the swipe which does not fire onChangeIndex callback. EG:
if (newItem.isViewable) {
setCurrentIndexes((prevState) => ({ ...prevState, index: nextIndex }));
}
I just had a quick look, I will try do some more investigation when I have some free time.
@curtismenmuir thanks for reporting the issue and the work-around, if you could take a deep look at it, it would be great 🙌
@curtismenmuir thanks for reporting the issue and the work-around, if you could take a deep look at it, it would be great 🙌
I also faced this issue. I noticed paginationIndex props of PaginationComponent always gives correct index. I found the value can be derived from parameters of onViewableItemsChanged. So here is my current workaround:
onViewableItemsChanged={(params) => console.log('index', params.changed?.[0]?.index)}
Same issue persist for me also. I have noticed that onchange index trigger after some delay. Any luck ?
I'm facing this issue , only when I swipe manually

It show half image, I need to show like this when i swipe manuall
y
Same issue persist for me also. I have noticed that onchange index trigger after some delay. Any luck ?
I'm facing the same delay issue... :(
+1 experiencing this issue!
+1 having the same issue when swipe manually.
figured out onMomentumScrollEnd solves the problem for now. Thanks @curtismenmuir
Instead this,
onChangeIndex={({ index }) => { setListIndex(index); }}
we can use this prop to get the index
onMomentumScrollEnd={({ index }: any) => setListIndex(index)}
onMomentumScrollEnd doesn't work on Android
+1 having issues where onChangeIndex doesn't update the index.
@ShobanaBohs100 onMomentumScrollEnd={({ index }: any) => setListIndex(index)} Thanks!!! this perfectly worked for IOS. but android still having same issue. What did you use for android?
+1
I did a few improvements (removing re-renders and adding support for getItemLayout), please use version 3.2.2 and let me know. Thanks
@gusgard Still the same issue on 3.2.2 :(
I wasn't able to reproduce it with Expo v48, is there an example or steps you can provide me ? @bravecode
i achieve this design and also created this code blog. https://buzzstuck.com/react-native-swiper-component-implemented-with-flatlist/
/node_modules/react-native-swiper-flatlist/src/components/SwiperFlatList/SwiperFlatList.tsx
const _onChangeIndex = React.useCallback(
({ index: _index, prevIndex: _prevIndex }: { index: number; prevIndex: number }) => {
// -> Moving it out of the condition can temporarily solve the issue. Another problem is that _onChangeIndex cannot be triggered immediately after the swipe, but needs to wait for a moment.
onChangeIndex?.({ index: _index, prevIndex: _prevIndex });
// -> First swipe right, then swipe left will not trigger _onChangeIndex.
if (_index !== _prevIndex) {
onChangeIndex?.({ index: _index, prevIndex: _prevIndex });
// onChangeIndex?.({ index: _index, prevIndex: _prevIndex });
}
},
[onChangeIndex]
+1
I have 6 items onChnageIndex is not firing after 3rd Index.
const renderItem = ({item, index}: {item: IHome; index: number}) => {
return (
<View height={height * 0.9} width={width}>
<Video
source={{
uri: item.attachmentUrl,
}}
paused={currentIndex !== index}
style={styles.video}
resizeMode="stretch"
// controls
onLoad={() => setLoading(false)}
onLoadStart={() => setLoading(true)}
onError={() => setLoading(false)}
repeat
/>
<View position={'absolute'} bottom={height * 0.1} right={5}>
<Pressable>
{item.is_Liked ? (
<SelectedLike height={7} width={7} />
) : (
<Likes height={7} width={7} />
)}
<Text
style={[
styles.text,
styles.count,
theme === 'light' ? styles.countLight : styles.countDark,
]}>
{formatCount(item.total_likes)}
</Text>
</Pressable>
<Pressable mt={5}>
<MessageGrey height={7} width={7} />
<Text
style={[
styles.text,
styles.count,
theme === 'light' ? styles.countLight : styles.countDark,
]}>
{formatCount(item.total_comments)}
</Text>
</Pressable>
<Pressable mt={5}>
<FavoritesWhite height={7} width={7} />
</Pressable>
</View>
<View
position={'absolute'}
bottom={height * 0.1}
left={5}
width={widthToDp(65)}>
<HStack>
<FastImage
style={styles.profilePic}
source={{uri: item.profile_pic}}
/>
<View ml={3}>
<Text
style={[
styles.text,
styles.fullName,
theme === 'light' ? styles.countLight : styles.countDark,
]}>
{item.full_name}
</Text>
<Text
style={[
styles.text,
styles.bio,
theme === 'light' ? styles.bioLight : styles.bioDark,
]}>
{item.user_bio}
</Text>
</View>
</HStack>
<Text
style={[
styles.text,
styles.bio,
theme === 'light' ? styles.countLight : styles.countDark,
]}>
{item.description}
</Text>
</View>
</View>
);
};
<SwiperFlatList
vertical
ref={flatListRef}
data={reels}
autoplay={false}
renderItem={renderItem}
onChangeIndex={({index, prevIndex}) => {
console.log('prev=>', prevIndex, 'current index=>', index);
setCurrentIndex(index);
}}
keyExtractor={item => item.id}
/>
If any one have any other work around for getting the index of current visible item then please let me know
I did a few improvements (removing re-renders and adding support for
getItemLayout), please use version3.2.2and let me know. Thanks
This worked for me! I was having this issue with onChangeIndex function, it would reach the third item in the array and stop counting. I'm using the list vertically and have a fixed header at the top with a height of 90px. I believe in this part of the code
if (props.getItemLayout === undefined) {
const itemDimension = vertical ? height : width;
flatListProps.getItemLayout = (__data, ItemIndex: number) => ({
length: itemDimension,
offset: itemDimension * ItemIndex,
index: ItemIndex,
});
}
the offset didn't match the height of the images in the list. I just needed to provide this information in the SwiperFlatList:
<SwiperFlatList
data={content}
renderItem={({index, item}) => renderItem({index, item})}
vertical
keyExtractor={item => item.itemId.toString()}
getItemLayout={(_d, i) => ({
length: Dimensions.get('window').height,
index: i,
offset: (Dimensions.get('window').height - 90) * i,
})}
onChangeIndex={({index, prevIndex}) => console.log(index)}
/>
Now the onChangeIndex function is correctly returning the visible index. I'm not sure if it applies to everyone here, but it worked for my case.
I can confirm that setting getItemLayout with correct dimensions triggers the onChangeIndex correctly, can it be added to the docs?
hey @devakrishna33 could you kindly share your code snippet?
same
Should be fixed in 3.2.4