-
-
Notifications
You must be signed in to change notification settings - Fork 981
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
Removing a nested gesture handler causes parent to become unresponsive #2688
Comments
Hi @computerjazz! We've looked into your code and it seems that it uses Gesture Handler in a wrong way. First of all, if you try to run this code on web, you'll get From what we can see, you're using a recursive component that receives gestures from parent as a prop, then you combine them in You can try to use simultaneousWithExternalGesture instead, maybe this will help. |
Thanks for the quick response @m-bert! I didn't know that a gesture can't/shouldn't be used across multiple I noticed |
I'm not sure why you used Correct me if I'm wrong, but in parent Edit: I've missed that |
In my toy example that would work, but I want to be able to support simultaneous composed gestures in react-native-infinite-pager. example where I want to wrap the It seems like the code works as expected when I use a composed gesture as a |
I've just tested that on a small example. Even though it looks like it works in your case, we can't guarantee that it will always be the case. I've prepared small repro to show what I mean: Example codeimport React from 'react';
import { View, StyleSheet } from 'react-native';
import { GestureDetector, Gesture } from 'react-native-gesture-handler';
export default function App() {
const outerPan1 = Gesture.Pan()
.activeOffsetX(20)
.onChange((e) => console.log(e.handlerTag));
const outerPan2 = Gesture.Pan()
.activeOffsetX(-20)
.onChange((e) => console.log(e.handlerTag));
const outerPan = Gesture.Simultaneous(outerPan1, outerPan2);
const innerPan = Gesture.Pan()
.onChange((e) => console.log(e.handlerTag))
.simultaneousWithExternalGesture(outerPan);
return (
<View style={styles.container}>
<GestureDetector gesture={outerPan}>
<View style={styles.box1}>
<GestureDetector gesture={innerPan}>
<View style={styles.box2} />
</GestureDetector>
</View>
</GestureDetector>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'space-around',
alignItems: 'center',
},
box1: {
width: 500,
height: 500,
backgroundColor: 'green',
display: 'flex',
justifyContent: 'space-around',
alignItems: 'center',
},
box2: {
width: 250,
height: 250,
backgroundColor: 'blue',
},
}); Code above has 2 boxes, outer one has 2 If you run code above you can see, that panning inside inner box will give logs with only one handler tag - that's why outer ones are not triggered. However, if you change this line: .simultaneousWithExternalGesture(outerPan); to this: .simultaneousWithExternalGesture(...outerPan.toGestureArray()); you can see all handlers tag being logged (given that they all meet activation criteria). |
Hi! I hope everything is clear now. Given that it was expected behavior, not a problem, I will close this issue. Feel free to re-open it, or submit a new one, if you find something that needs to be addressed. |
Thanks for all your help @m-bert ! Yes, all clear now, although it might be useful to more clearly document the different ways multiple gestures can be defined (and warn against doing what I did 😅). Maybe also a console warning with info on how to fix if multiple gesture detectors try to register the same gesture? |
…stureDetectors` (#2694) ## Description Some of our users incorrectly use gesture handlers - they pass the same gesture handler instance into multiple `GestureDetectors`. It very often leads to unexpected behavior, like described in #2688. Currently web version of our library throws error `Handler with tag x already exists`. However, there are 2 problems with that: 1. This error message is not really helpful in case of fixing that problem. 2. Native platforms do not perform this check, so people don't know that they're using our handlers in a wrong way. This PR: - Improves error message - Adds check on native platforms - Adds information about error in `GestureDetector` documentation in remarks section ## Test plan Tested with code below on all platforms. <details> <summary>Code that throws error</summary> ```jsx import React from 'react'; import { View } from 'react-native'; import { Gesture, GestureDetector } from 'react-native-gesture-handler'; export default function Example() { const pan = Gesture.Pan(); return ( <View> <GestureDetector gesture={pan}> <View> <GestureDetector gesture={pan}> <View /> </GestureDetector> </View> </GestureDetector> </View> ); } ``` </details>
Description
If gesture handlers are nested with
simultaneousHandlers
enabled, removing the inner handler causes the outer handler to become unresponsive. This is true whether the inner handler is removed while a gesture is in progress or not.There is a workaround — including
myGesture.initialize()
in auseEffect
fixes it, though I'm not sure why.In the video below I'm removing the child 1 second after beginning the gesture. In the "broken" case, the gesture immediately becomes unresponsive when the child is removed, and subsequent drags also do not work. In the "fixed" case with the workaround above, everything works as expected:
Steps to reproduce
simultaneousHandlers
with parent handlersSnack or a link to a repository
https://snack.expo.dev/@easydan/removing-nested-handler-bug
Gesture Handler version
2.13.4
React Native version
0.72.3
Platforms
iOS
JavaScript runtime
Hermes
Workflow
Expo managed workflow
Architecture
Paper (Old Architecture)
Build type
Release mode
Device
Real device
Device model
iPhone 15 Pro
Acknowledgements
Yes
The text was updated successfully, but these errors were encountered: