jshanson7/react-native-swipeable

Action is being triggered more than once

avishayil opened this issue · 14 comments

                leftContent={leftContent}
                rightContent={rightContent}
                onRightActionComplete={() => {
                    console.log("Right Action Complete");
                }}
                onLeftActionComplete={() => {
                    console.log("Left Action Complete");
                }}

When playing swiping and swiping back while holding the swipeable action open, the action triggers countless times.

When swiping quickly, action triggers twice.

Also, this warning sometimes appear:

Possible Unhandled Promise Rejection (id: 13):

Actually, I partly solved it using onRightActionRelease instead of onRightActionComplete, but I still get the warning of possible unhandled promise rejection.

@avishayil thanks for reporting -- are you on iOS or android? And was it only 'onRightActionComplete' that fired multiple times? Or the left side as well?

Just added some log statements to the example and the lifecycle callbacks seem to be working correctly for me on iOS:
jan-15-2017 10-48-50
Also tried swiping quickly, but didn't see anything strange.

Maybe i'm doing something wrong here (Ignore the Hebrew), and maybe it's the ListView that causes problems, notice the last part of the GIF:

                leftContent={(
                    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'flex-end', paddingRight: 20, backgroundColor: (this.state.leftActionActivated ? (!appStore.favoriteExists(story.id) ? '#00897b' : '#d32f2f') : '#ffab00') }}>
                        <View style={{ justifyContent: 'center', alignItems: 'center' }}>
                            <Icon name="add-to-favorites" style={{ color: '#ffffff' }} />
                            <Text style={{ color: '#ffffff' }}>{!appStore.favoriteExists(story.id) ? "הוסף למועדפים" : "הסר מהמועדפים"}</Text>
                        </View>
                    </View>
                )}
                onLeftActionActivate={() => this.setState({ leftActionActivated: true })}
                onLeftActionDeactivate={() => this.setState({ leftActionActivated: false })}
                leftActionActivationDistance={200}
                onLeftActionRelease={() => {
                    !appStore.favoriteExists(story.id) ? appStore.add(story.id) : appStore.remove(story.id);
                    this.swipeable.recenter();
                    this.setState({ toggle: !this.state.toggle });
                } }

image

Hmm the this.swipeable.recenter(); is unnecessary in onLeftActionRelease as it should recenter itself automatically on release -- the recenter method is for recentering programmatically when buttons are exposed.

The gif looks pretty choppy (maybe log statements?), so it's hard to tell what's going on. onLeftActionRelease is fired right when you let go of the row, so you'll see your row flash red while it's sliding back to center. If you don't want to see that color change as it's transitioning, you can change it to onLeftActionComplete and it will wait until it's done transitioning to toggle the appStore favorite. I would try playing with it a bit with debug=false to get a feel of how it will really behave.

Hi, im having a similar issue even using onRightActionRelease. It seams to be that if a vertical scroll is made while swiping it triggers onRightActionRelease.

I dont remember if native components for iOS when swiping allow to scroll vertically, but that seems to be the way to solve this.

Interesting, @indesignlatam is there any way you can reproduce this with some sample code that I can run in my simulator? The Swipeable component should prevent vertical scrolling by becoming the pan responder once you've swiped horizontally past the swipeStartMinDistance threshold. Are you using a custom ListView/ScrollView?

Hi @jshanson7, im using the the List component of Native Base and the MeteorComplexListView of the react-native-meteor package. Is there something I should do to make it work?

@indesignlatam @avishayil I figured out the problem -- you need to set scrollEnabled={!isSwiping} on your ScrollView, or else Swipeable and your ScrollView will quickly alternate as the pan responder, causing all kinds of issues (see facebook/react-native#1046).

<ScrollView scrollEnabled={!this.state.isSwiping}>
  <Swipeable
    onSwipeStart={() => this.setState({isSwiping: true})}
    onSwipeRelease={() => this.setState({isSwiping: false})}
  </Swipeable>
</ScrollView>

See also: http://browniefed.com/blog/react-native-pan-responder-inside-of-a-scrollview/

Open to good ways to detect/prevent this within the Swipeable component. I'd prefer not to release a customized ScrollView/ListView and force people to use that. For the time being I will add a ScrollView example and make a note of this issue in the Readme.

Great, I think adding this to the documentation is enough to start.

I dont know of a way to set the parent props or state without a callback, if that is not possible the only thing that I can think of is a prop that returns the isSwiping state of the Swiper so that there is only 1 callback to pass as a prop.

<ScrollView scrollEnabled={ !this.state.isSwiping }>
  <Swipeable
    onSwipe={ (isSwiping) => this.setState({ isSwiping }) }>
  </Swipeable>
</ScrollView>

Hello,

I encountered the same problem: my action is being triggered countless times when I swipe vertically while swiping horizontally. So I implemented @jshanson7's solution.
Nevertheless there are still problems with this solution:

  • The swipe takes a bit of time to start because the setState makes the scrollView rerender, .
  • If you swipe diagonally (and quickly), the action is being triggered many times.

What could be done to solve these problems?
Thanks in advance

I hate to say this, but I had to switch over to https://github.com/jemise111/react-native-swipe-list-view because of this issue. When I swipe diagonally, the actions were still triggered(and bad user experience...) I stopped trying to figure out the work around. Too much of headache...

kopax commented

This is not fixed, I have tried with :

<ScrollView scrollEnabled={!this.state.isSwiping}>
  <Swipeable
    onSwipeStart={() => this.setState({isSwiping: true})}
    onSwipeRelease={() => this.setState({isSwiping: false})}
  </Swipeable>
</ScrollView>

after that, I am not able to scroll down on any of my devices.