diff --git a/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerModule.kt b/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerModule.kt index d786284053..d242eb6f11 100644 --- a/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerModule.kt +++ b/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerModule.kt @@ -340,6 +340,13 @@ class RNGestureHandlerModule(reactContext: ReactApplicationContext?) : handlerTag: Int, config: ReadableMap, ) { + + if (registry.getHandler(handlerTag) !== null) { + throw IllegalStateException( + "Handler with tag $handlerTag already exists. Please ensure that no Gesture instance is used across multiple GestureDetectors." + ) + } + for (handlerFactory in handlerFactories as Array>) { if (handlerFactory.name == handlerName) { val handler = handlerFactory.create(reactApplicationContext).apply { diff --git a/apple/RNGestureHandlerManager.mm b/apple/RNGestureHandlerManager.mm index d5158826f6..83d9058762 100644 --- a/apple/RNGestureHandlerManager.mm +++ b/apple/RNGestureHandlerManager.mm @@ -71,6 +71,14 @@ - (instancetype)initWithUIManager:(RCTUIManager *)uiManager eventDispatcher:(RCT - (void)createGestureHandler:(NSString *)handlerName tag:(NSNumber *)handlerTag config:(NSDictionary *)config { + if ([_registry handlerWithTag:handlerTag] != nullptr) { + NSString *errorMessage = [NSString + stringWithFormat: + @"Handler with tag %@ already exists. Please ensure that no Gesture instance is used across multiple GestureDetectors.", + handlerTag]; + @throw [NSException exceptionWithName:@"HandlerAlreadyRegistered" reason:errorMessage userInfo:nil]; + } + static NSDictionary *map; static dispatch_once_t mapToken; dispatch_once(&mapToken, ^{ diff --git a/docs/docs/gestures/gesture-detector.md b/docs/docs/gestures/gesture-detector.md index bab53b6b11..335672f22d 100644 --- a/docs/docs/gestures/gesture-detector.md +++ b/docs/docs/gestures/gesture-detector.md @@ -47,3 +47,25 @@ This parameter allows to specify which `userSelect` property should be applied t - Gesture Detector will use first native view in its subtree to recognize gestures, however if this view is used only to group its children it may get automatically [collapsed](https://reactnative.dev/docs/view#collapsable-android). Consider this example: If we were to remove the collapsable prop from the View, the gesture would stop working because it would be attached to a view that is not present in the view hierarchy. Gesture Detector adds this prop automatically to its direct child but it's impossible to do automatically for more complex view trees. + +- Using the same instance of a gesture across multiple Gesture Detectors is not possible. Have a look at the code below: + + ```jsx + export default function Example() { + const pan = Gesture.Pan(); + + return ( + + + + {/* Don't do this! */} + + + + + + ); + } + ``` + + This example will throw an error, becuse we try to use the same instance of `Pan` in two different Gesture Detectors. diff --git a/src/web/tools/NodeManager.ts b/src/web/tools/NodeManager.ts index 825f4d0f84..fd4a9c630c 100644 --- a/src/web/tools/NodeManager.ts +++ b/src/web/tools/NodeManager.ts @@ -21,7 +21,9 @@ export default abstract class NodeManager { handler: InstanceType> ): void { if (handlerTag in this.gestures) { - throw new Error(`Handler with tag ${handlerTag} already exists`); + throw new Error( + `Handler with tag ${handlerTag} already exists. Please ensure that no Gesture instance is used across multiple GestureDetectors.` + ); } this.gestures[handlerTag] = handler;