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

onChangeIndex() doesn't always fire when using swipe feature #110

Closed
curtismenmuir opened this issue Mar 19, 2021 · 29 comments
Closed

onChangeIndex() doesn't always fire when using swipe feature #110

curtismenmuir opened this issue Mar 19, 2021 · 29 comments
Assignees

Comments

@curtismenmuir
Copy link
Contributor

curtismenmuir commented Mar 19, 2021

Description

  • When user manually swipes item to side numerous times, onChangeIndex callback 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 in v0.62.2)
  • react-native-swiper-flatlist version: 3.0.14 (also seen in v3.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
@curtismenmuir
Copy link
Contributor Author

I have found a work-around by also implementing onMomentumScrollEnd callback. Leaving this issue open incase you want to track the onChangeIndex issue.

@curtismenmuir
Copy link
Contributor Author

curtismenmuir commented Mar 20, 2021

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.

@gusgard gusgard self-assigned this Apr 1, 2021
@gusgard
Copy link
Owner

gusgard commented Apr 1, 2021

@curtismenmuir thanks for reporting the issue and the work-around, if you could take a deep look at it, it would be great 🙌

1 similar comment
@gusgard
Copy link
Owner

gusgard commented Apr 1, 2021

@curtismenmuir thanks for reporting the issue and the work-around, if you could take a deep look at it, it would be great 🙌

@PaperMonster
Copy link

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

@arcsoftanil
Copy link

Same issue persist for me also. I have noticed that onchange index trigger after some delay. Any luck ?

@Priyadharshini-max
Copy link

I'm facing this issue , only when I swipe manually
Screenshot_2022-06-03-12-43-05-61_4007cdf3d38763fe5bc19f163cbad3b9__01
Screenshot_2022-06-03-12-43-02-16_4007cdf3d38763fe5bc19f163cbad3b9__01

@Priyadharshini-max
Copy link

It show half image, I need to show like this when i swipe manuall
Screenshot_2022-06-03-12-46-57-04_4007cdf3d38763fe5bc19f163cbad3b9__01
y

@iortega-dev
Copy link

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

@zachnicoll
Copy link

zachnicoll commented Sep 11, 2022

+1 experiencing this issue!

@ShobanaBohs100
Copy link

ShobanaBohs100 commented Sep 20, 2022

+1 having the same issue when swipe manually.

@ShobanaBohs100
Copy link

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

@garrettg123
Copy link

onMomentumScrollEnd doesn't work on Android

@apethree
Copy link

+1 having issues where onChangeIndex doesn't update the index.

@varunkukade
Copy link

@ShobanaBohs100 onMomentumScrollEnd={({ index }: any) => setListIndex(index)} Thanks!!! this perfectly worked for IOS. but android still having same issue. What did you use for android?

@DanielRiera
Copy link

+1

@gusgard
Copy link
Owner

gusgard commented Apr 23, 2023

I did a few improvements (removing re-renders and adding support for getItemLayout), please use version 3.2.2 and let me know. Thanks

@bravecode
Copy link

@gusgard Still the same issue on 3.2.2 :(

@gusgard
Copy link
Owner

gusgard commented Apr 27, 2023

I wasn't able to reproduce it with Expo v48, is there an example or steps you can provide me ? @bravecode

@kishanvaghera
Copy link

i achieve this design and also created this code blog.
https://buzzstuck.com/react-native-swiper-component-implemented-with-flatlist/

@gusgard gusgard closed this as completed Jun 8, 2023
@Riuhou
Copy link

Riuhou commented Jun 14, 2023

/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]

@gusgard gusgard reopened this Jun 16, 2023
@iamsaadMehmood
Copy link

iamsaadMehmood commented Jun 19, 2023

+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}
          />
          

@dprajapati1179
Copy link

If any one have any other work around for getting the index of current visible item then please let me know

@douglas-esportudo
Copy link

I did a few improvements (removing re-renders and adding support for getItemLayout), please use version 3.2.2 and 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.

@devakrishna33
Copy link

I can confirm that setting getItemLayout with correct dimensions triggers the onChangeIndex correctly, can it be added to the docs?

@lsps9150414
Copy link

hey @devakrishna33 could you kindly share your code snippet?

@BLOCKMATERIAL
Copy link

same

@gusgard
Copy link
Owner

gusgard commented Apr 23, 2024

Should be fixed in 3.2.4

@gusgard gusgard closed this as not planned Won't fix, can't repro, duplicate, stale May 1, 2024
@Qurat-ul-ainn
Copy link

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

by using this getting an error "Changing onViewableChanged on the fly is not supported"

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

No branches or pull requests