react-native-gesture-handler 2.8.0 → 2.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. package/RNGestureHandler.podspec +1 -1
  2. package/android/build.gradle +45 -43
  3. package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerButtonViewManager.kt +1 -0
  4. package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerEvent.kt +14 -2
  5. package/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerModule.kt +5 -1
  6. package/android/src/main/jni/CMakeLists.txt +10 -44
  7. package/android/src/main/jni/cpp-adapter.cpp +16 -13
  8. package/ios/Handlers/RNFlingHandler.m +39 -37
  9. package/ios/Handlers/RNForceTouchHandler.m +19 -17
  10. package/ios/Handlers/RNLongPressHandler.m +20 -22
  11. package/ios/Handlers/RNManualHandler.m +2 -3
  12. package/ios/Handlers/RNNativeViewHandler.mm +92 -88
  13. package/ios/Handlers/RNPanHandler.m +28 -32
  14. package/ios/Handlers/RNPinchHandler.m +9 -10
  15. package/ios/Handlers/RNRotationHandler.m +11 -14
  16. package/ios/Handlers/RNTapHandler.m +26 -26
  17. package/ios/RNGestureHandler.h +31 -24
  18. package/ios/RNGestureHandler.m +278 -273
  19. package/ios/RNGestureHandlerActionType.h +6 -4
  20. package/ios/RNGestureHandlerButton.m +11 -12
  21. package/ios/RNGestureHandlerButtonManager.m +6 -5
  22. package/ios/RNGestureHandlerDirection.h +4 -4
  23. package/ios/RNGestureHandlerEvents.h +3 -4
  24. package/ios/RNGestureHandlerEvents.m +114 -119
  25. package/ios/RNGestureHandlerManager.h +1 -2
  26. package/ios/RNGestureHandlerModule.h +1 -2
  27. package/ios/RNGestureHandlerModule.mm +126 -122
  28. package/ios/RNGestureHandlerPointerTracker.h +1 -1
  29. package/ios/RNGestureHandlerPointerTracker.m +40 -37
  30. package/ios/RNGestureHandlerRegistry.h +3 -1
  31. package/ios/RNGestureHandlerRegistry.m +24 -22
  32. package/ios/RNGestureHandlerState.h +6 -6
  33. package/ios/RNGestureHandlerStateManager.h +1 -1
  34. package/ios/RNManualActivationRecognizer.m +9 -9
  35. package/ios/RNRootViewGestureRecognizer.m +36 -39
  36. package/lib/commonjs/components/DrawerLayout.js.map +1 -1
  37. package/lib/commonjs/components/Swipeable.js.map +1 -1
  38. package/lib/commonjs/gestureHandlerRootHOC.js +2 -1
  39. package/lib/commonjs/gestureHandlerRootHOC.js.map +1 -1
  40. package/lib/commonjs/handlers/LongPressGestureHandler.js +3 -1
  41. package/lib/commonjs/handlers/LongPressGestureHandler.js.map +1 -1
  42. package/lib/commonjs/handlers/TapGestureHandler.js +3 -1
  43. package/lib/commonjs/handlers/TapGestureHandler.js.map +1 -1
  44. package/lib/commonjs/handlers/gestures/GestureDetector.js +70 -28
  45. package/lib/commonjs/handlers/gestures/GestureDetector.js.map +1 -1
  46. package/lib/commonjs/handlers/gestures/longPressGesture.js +1 -0
  47. package/lib/commonjs/handlers/gestures/longPressGesture.js.map +1 -1
  48. package/lib/commonjs/handlers/gestures/tapGesture.js +1 -0
  49. package/lib/commonjs/handlers/gestures/tapGesture.js.map +1 -1
  50. package/lib/commonjs/web/handlers/LongPressGestureHandler.js +0 -1
  51. package/lib/commonjs/web/handlers/LongPressGestureHandler.js.map +1 -1
  52. package/lib/commonjs/web/handlers/TapGestureHandler.js +0 -1
  53. package/lib/commonjs/web/handlers/TapGestureHandler.js.map +1 -1
  54. package/lib/module/components/DrawerLayout.js.map +1 -1
  55. package/lib/module/components/Swipeable.js.map +1 -1
  56. package/lib/module/gestureHandlerRootHOC.js +2 -1
  57. package/lib/module/gestureHandlerRootHOC.js.map +1 -1
  58. package/lib/module/handlers/LongPressGestureHandler.js +3 -1
  59. package/lib/module/handlers/LongPressGestureHandler.js.map +1 -1
  60. package/lib/module/handlers/TapGestureHandler.js +3 -1
  61. package/lib/module/handlers/TapGestureHandler.js.map +1 -1
  62. package/lib/module/handlers/gestures/GestureDetector.js +72 -29
  63. package/lib/module/handlers/gestures/GestureDetector.js.map +1 -1
  64. package/lib/module/handlers/gestures/longPressGesture.js +1 -0
  65. package/lib/module/handlers/gestures/longPressGesture.js.map +1 -1
  66. package/lib/module/handlers/gestures/tapGesture.js +1 -0
  67. package/lib/module/handlers/gestures/tapGesture.js.map +1 -1
  68. package/lib/module/web/handlers/LongPressGestureHandler.js +0 -1
  69. package/lib/module/web/handlers/LongPressGestureHandler.js.map +1 -1
  70. package/lib/module/web/handlers/TapGestureHandler.js +0 -1
  71. package/lib/module/web/handlers/TapGestureHandler.js.map +1 -1
  72. package/lib/typescript/components/DrawerLayout.d.ts +3 -1
  73. package/lib/typescript/components/Swipeable.d.ts +3 -2
  74. package/lib/typescript/fabric/RNGestureHandlerButtonNativeComponent.d.ts +1 -1
  75. package/lib/typescript/fabric/RNGestureHandlerRootViewNativeComponent.d.ts +1 -1
  76. package/lib/typescript/gestureHandlerRootHOC.d.ts +1 -1
  77. package/package.json +4 -5
  78. package/src/components/DrawerLayout.tsx +8 -4
  79. package/src/components/Swipeable.tsx +14 -9
  80. package/src/gestureHandlerRootHOC.tsx +4 -1
  81. package/src/handlers/LongPressGestureHandler.ts +3 -1
  82. package/src/handlers/TapGestureHandler.ts +3 -1
  83. package/src/handlers/gestures/GestureDetector.tsx +81 -28
  84. package/src/handlers/gestures/longPressGesture.ts +1 -0
  85. package/src/handlers/gestures/tapGesture.ts +1 -0
  86. package/src/web/handlers/LongPressGestureHandler.ts +0 -1
  87. package/src/web/handlers/TapGestureHandler.ts +0 -1
@@ -3,6 +3,7 @@ import { Component } from 'react';
3
3
  import { Animated, StyleProp, ViewStyle } from 'react-native';
4
4
  import { PanGestureHandlerProps } from '../handlers/PanGestureHandler';
5
5
  declare type SwipeableExcludes = Exclude<keyof PanGestureHandlerProps, 'onGestureEvent' | 'onHandlerStateChange'>;
6
+ declare type AnimatedInterpolation = ReturnType<Animated.Value['interpolate']>;
6
7
  export interface SwipeableProps extends Pick<PanGestureHandlerProps, SwipeableExcludes> {
7
8
  /**
8
9
  * Enables two-finger gestures on supported devices, for example iPads with
@@ -97,7 +98,7 @@ export interface SwipeableProps extends Pick<PanGestureHandlerProps, SwipeableEx
97
98
  *
98
99
  * To support `rtl` flexbox layouts use `flexDirection` styling.
99
100
  * */
100
- renderLeftActions?: (progressAnimatedValue: Animated.AnimatedInterpolation, dragAnimatedValue: Animated.AnimatedInterpolation) => React.ReactNode;
101
+ renderLeftActions?: (progressAnimatedValue: AnimatedInterpolation, dragAnimatedValue: AnimatedInterpolation) => React.ReactNode;
101
102
  /**
102
103
  *
103
104
  * This map describes the values to use as inputRange for extra interpolation:
@@ -107,7 +108,7 @@ export interface SwipeableProps extends Pick<PanGestureHandlerProps, SwipeableEx
107
108
  *
108
109
  * To support `rtl` flexbox layouts use `flexDirection` styling.
109
110
  * */
110
- renderRightActions?: (progressAnimatedValue: Animated.AnimatedInterpolation, dragAnimatedValue: Animated.AnimatedInterpolation, swipeable: Swipeable) => React.ReactNode;
111
+ renderRightActions?: (progressAnimatedValue: AnimatedInterpolation, dragAnimatedValue: AnimatedInterpolation, swipeable: Swipeable) => React.ReactNode;
111
112
  useNativeAnimations?: boolean;
112
113
  animationOptions?: Record<string, unknown>;
113
114
  /**
@@ -1,4 +1,4 @@
1
- /// <reference types="react-native/codegen" />
1
+ /// <reference types="react-native/types/modules/codegen" />
2
2
  import type { Int32, WithDefault } from 'react-native/Libraries/Types/CodegenTypes';
3
3
  import type { ViewProps, ColorValue } from 'react-native';
4
4
  interface NativeProps extends ViewProps {
@@ -1,4 +1,4 @@
1
- /// <reference types="react-native/codegen" />
1
+ /// <reference types="react-native/types/modules/codegen" />
2
2
  import type { ViewProps } from 'react-native';
3
3
  interface NativeProps extends ViewProps {
4
4
  }
@@ -1,3 +1,3 @@
1
1
  import * as React from 'react';
2
2
  import { StyleProp, ViewStyle } from 'react-native';
3
- export default function gestureHandlerRootHOC<P>(Component: React.ComponentType<P>, containerStyles?: StyleProp<ViewStyle>): React.ComponentType<P>;
3
+ export default function gestureHandlerRootHOC<P extends JSX.IntrinsicAttributes>(Component: React.ComponentType<P>, containerStyles?: StyleProp<ViewStyle>): React.ComponentType<P>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-gesture-handler",
3
- "version": "2.8.0",
3
+ "version": "2.9.0",
4
4
  "description": "Experimental implementation of a new declarative API for gesture handling in react-native",
5
5
  "scripts": {
6
6
  "prepare": "bob build && husky install",
@@ -82,8 +82,7 @@
82
82
  "@types/hammerjs": "^2.0.38",
83
83
  "@types/hoist-non-react-statics": "^3.3.1",
84
84
  "@types/jest": "^27.0.3",
85
- "@types/react": "^17.0.0",
86
- "@types/react-native": "^0.69.6",
85
+ "@types/react": "^18.0.24",
87
86
  "@types/react-test-renderer": "^17.0.0",
88
87
  "@typescript-eslint/eslint-plugin": "^4.33.0",
89
88
  "@typescript-eslint/parser": "^4.33.0",
@@ -100,9 +99,9 @@
100
99
  "lint-staged": "^12.3.2",
101
100
  "metro-react-native-babel-preset": "^0.64.0",
102
101
  "prettier": "^2.7.1",
103
- "react": "^16.8.6",
102
+ "react": "18.2.0",
104
103
  "react-dom": "^16.12.0",
105
- "react-native": "^0.64.0",
104
+ "react-native": "0.71.0",
106
105
  "react-native-builder-bob": "^0.17.1",
107
106
  "react-native-reanimated": "^2.3.1",
108
107
  "react-native-web": "^0.11.7",
@@ -54,6 +54,10 @@ export type DrawerLockMode = 'unlocked' | 'locked-closed' | 'locked-open';
54
54
 
55
55
  export type DrawerKeyboardDismissMode = 'none' | 'on-drag';
56
56
 
57
+ // Animated.AnimatedInterpolation has been converted to a generic type
58
+ // in @types/react-native 0.70. This way we can maintain compatibility
59
+ // with all versions of @types/react-native`
60
+ type AnimatedInterpolation = ReturnType<Animated.Value['interpolate']>;
57
61
  export interface DrawerLayoutProps {
58
62
  /**
59
63
  * This attribute is present in the standard implementation already and is one
@@ -153,7 +157,7 @@ export interface DrawerLayoutProps {
153
157
  // implicit `children` prop has been removed in @types/react^18.0.0
154
158
  children?:
155
159
  | React.ReactNode
156
- | ((openValue?: Animated.AnimatedInterpolation) => React.ReactNode);
160
+ | ((openValue?: AnimatedInterpolation) => React.ReactNode);
157
161
 
158
162
  /**
159
163
  * @default 'none'
@@ -224,7 +228,7 @@ export default class DrawerLayout extends Component<
224
228
  return true;
225
229
  }
226
230
 
227
- private openValue?: Animated.AnimatedInterpolation;
231
+ private openValue?: AnimatedInterpolation;
228
232
  private onGestureEvent?: (
229
233
  event: GestureEvent<PanGestureHandlerEventPayload>
230
234
  ) => void;
@@ -603,7 +607,7 @@ export default class DrawerLayout extends Component<
603
607
  };
604
608
  }
605
609
 
606
- let drawerTranslateX: number | Animated.AnimatedInterpolation = 0;
610
+ let drawerTranslateX: number | AnimatedInterpolation = 0;
607
611
  if (drawerSlide) {
608
612
  const closedDrawerOffset = fromLeft ? -drawerWidth! : drawerWidth!;
609
613
  if (this.state.drawerState !== IDLE) {
@@ -617,7 +621,7 @@ export default class DrawerLayout extends Component<
617
621
  }
618
622
  }
619
623
  const drawerStyles: {
620
- transform: { translateX: number | Animated.AnimatedInterpolation }[];
624
+ transform: { translateX: number | AnimatedInterpolation }[];
621
625
  flexDirection: 'row-reverse' | 'row';
622
626
  } = {
623
627
  transform: [{ translateX: drawerTranslateX }],
@@ -36,6 +36,11 @@ type SwipeableExcludes = Exclude<
36
36
  'onGestureEvent' | 'onHandlerStateChange'
37
37
  >;
38
38
 
39
+ // Animated.AnimatedInterpolation has been converted to a generic type
40
+ // in @types/react-native 0.70. This way we can maintain compatibility
41
+ // with all versions of @types/react-native
42
+ type AnimatedInterpolation = ReturnType<Animated.Value['interpolate']>;
43
+
39
44
  export interface SwipeableProps
40
45
  extends Pick<PanGestureHandlerProps, SwipeableExcludes> {
41
46
  /**
@@ -150,8 +155,8 @@ export interface SwipeableProps
150
155
  * To support `rtl` flexbox layouts use `flexDirection` styling.
151
156
  * */
152
157
  renderLeftActions?: (
153
- progressAnimatedValue: Animated.AnimatedInterpolation,
154
- dragAnimatedValue: Animated.AnimatedInterpolation
158
+ progressAnimatedValue: AnimatedInterpolation,
159
+ dragAnimatedValue: AnimatedInterpolation
155
160
  ) => React.ReactNode;
156
161
  /**
157
162
  *
@@ -163,8 +168,8 @@ export interface SwipeableProps
163
168
  * To support `rtl` flexbox layouts use `flexDirection` styling.
164
169
  * */
165
170
  renderRightActions?: (
166
- progressAnimatedValue: Animated.AnimatedInterpolation,
167
- dragAnimatedValue: Animated.AnimatedInterpolation,
171
+ progressAnimatedValue: AnimatedInterpolation,
172
+ dragAnimatedValue: AnimatedInterpolation,
168
173
  swipeable: Swipeable
169
174
  ) => React.ReactNode;
170
175
 
@@ -242,11 +247,11 @@ export default class Swipeable extends Component<
242
247
  private onGestureEvent?: (
243
248
  event: GestureEvent<PanGestureHandlerEventPayload>
244
249
  ) => void;
245
- private transX?: Animated.AnimatedInterpolation;
246
- private showLeftAction?: Animated.AnimatedInterpolation | Animated.Value;
247
- private leftActionTranslate?: Animated.AnimatedInterpolation;
248
- private showRightAction?: Animated.AnimatedInterpolation | Animated.Value;
249
- private rightActionTranslate?: Animated.AnimatedInterpolation;
250
+ private transX?: AnimatedInterpolation;
251
+ private showLeftAction?: AnimatedInterpolation | Animated.Value;
252
+ private leftActionTranslate?: AnimatedInterpolation;
253
+ private showRightAction?: AnimatedInterpolation | Animated.Value;
254
+ private rightActionTranslate?: AnimatedInterpolation;
250
255
 
251
256
  private updateAnimatedEvent = (
252
257
  props: SwipeableProps,
@@ -3,7 +3,9 @@ import { StyleSheet, StyleProp, ViewStyle } from 'react-native';
3
3
  import hoistNonReactStatics from 'hoist-non-react-statics';
4
4
  import GestureHandlerRootView from './GestureHandlerRootView';
5
5
 
6
- export default function gestureHandlerRootHOC<P>(
6
+ export default function gestureHandlerRootHOC<
7
+ P extends JSX.IntrinsicAttributes
8
+ >(
7
9
  Component: React.ComponentType<P>,
8
10
  containerStyles?: StyleProp<ViewStyle>
9
11
  ): React.ComponentType<P> {
@@ -19,6 +21,7 @@ export default function gestureHandlerRootHOC<P>(
19
21
  Component.displayName || Component.name
20
22
  })`;
21
23
 
24
+ // @ts-ignore - hoistNonReactStatics uses old version of @types/react
22
25
  hoistNonReactStatics(Wrapper, Component);
23
26
 
24
27
  return Wrapper;
@@ -82,5 +82,7 @@ export const LongPressGestureHandler = createHandler<
82
82
  ...baseGestureHandlerProps,
83
83
  ...longPressGestureHandlerProps,
84
84
  ] as const,
85
- config: {},
85
+ config: {
86
+ shouldCancelWhenOutside: true,
87
+ },
86
88
  });
@@ -88,5 +88,7 @@ export const TapGestureHandler = createHandler<
88
88
  ...baseGestureHandlerProps,
89
89
  ...tapGestureHandlerProps,
90
90
  ] as const,
91
- config: {},
91
+ config: {
92
+ shouldCancelWhenOutside: true,
93
+ },
92
94
  });
@@ -1,4 +1,4 @@
1
- import React, { useEffect, useRef, RefObject } from 'react';
1
+ import React, { useEffect, useRef, useState } from 'react';
2
2
  import {
3
3
  GestureType,
4
4
  HandlerCallbacks,
@@ -130,6 +130,7 @@ interface AttachHandlersConfig {
130
130
  gesture: GestureType[];
131
131
  viewTag: number;
132
132
  webEventHandlersRef: React.RefObject<WebEventHandler>;
133
+ mountedRef: React.RefObject<boolean>;
133
134
  }
134
135
 
135
136
  function attachHandlers({
@@ -138,6 +139,7 @@ function attachHandlers({
138
139
  gesture,
139
140
  viewTag,
140
141
  webEventHandlersRef,
142
+ mountedRef,
141
143
  }: AttachHandlersConfig) {
142
144
  if (!preparedGesture.firstExecution) {
143
145
  gestureConfig.initialize();
@@ -148,6 +150,9 @@ function attachHandlers({
148
150
  // use setImmediate to extract handlerTags, because all refs should be initialized
149
151
  // when it's ran
150
152
  setImmediate(() => {
153
+ if (!mountedRef.current) {
154
+ return;
155
+ }
151
156
  gestureConfig.prepare();
152
157
  });
153
158
 
@@ -165,6 +170,9 @@ function attachHandlers({
165
170
  // use setImmediate to extract handlerTags, because all refs should be initialized
166
171
  // when it's ran
167
172
  setImmediate(() => {
173
+ if (!mountedRef.current) {
174
+ return;
175
+ }
168
176
  for (const handler of gesture) {
169
177
  let requireToFail: number[] = [];
170
178
  if (handler.config.requireToFail) {
@@ -230,7 +238,7 @@ function updateHandlers(
230
238
  preparedGesture: GestureConfigReference,
231
239
  gestureConfig: ComposedGesture | GestureType,
232
240
  gesture: GestureType[],
233
- mountedRef: RefObject<boolean>
241
+ mountedRef: React.RefObject<boolean>
234
242
  ) {
235
243
  gestureConfig.prepare();
236
244
 
@@ -588,6 +596,12 @@ interface GestureDetectorProps {
588
596
  userSelect?: UserSelect;
589
597
  children?: React.ReactNode;
590
598
  }
599
+ interface GestureDetectorState {
600
+ firstRender: boolean;
601
+ viewRef: React.Component | null;
602
+ previousViewTag: number;
603
+ forceReattach: boolean;
604
+ }
591
605
  export const GestureDetector = (props: GestureDetectorProps) => {
592
606
  const gestureConfig = props.gesture;
593
607
 
@@ -597,8 +611,14 @@ export const GestureDetector = (props: GestureDetectorProps) => {
597
611
 
598
612
  const gesture = gestureConfig.toGestureArray();
599
613
  const useReanimatedHook = gesture.some((g) => g.shouldUseReanimated);
600
- const viewRef = useRef(null);
601
- const firstRenderRef = useRef(true);
614
+
615
+ // store state in ref to prevent unnecessary renders
616
+ const state = useRef<GestureDetectorState>({
617
+ firstRender: true,
618
+ viewRef: null,
619
+ previousViewTag: -1,
620
+ forceReattach: false,
621
+ }).current;
602
622
  const mountedRef = useRef(false);
603
623
  const webEventHandlersRef = useRef<WebEventHandler>({
604
624
  onGestureHandlerEvent: (e: HandlerStateChangeEvent<unknown>) => {
@@ -611,6 +631,11 @@ export const GestureDetector = (props: GestureDetectorProps) => {
611
631
  : undefined,
612
632
  });
613
633
 
634
+ const [renderState, setRenderState] = useState(false);
635
+ function forceRender() {
636
+ setRenderState(!renderState);
637
+ }
638
+
614
639
  const preparedGesture = React.useRef<GestureConfigReference>({
615
640
  config: gesture,
616
641
  animatedEventHandler: null,
@@ -627,10 +652,41 @@ export const GestureDetector = (props: GestureDetectorProps) => {
627
652
  );
628
653
  }
629
654
 
655
+ function onHandlersUpdate(skipConfigUpdate?: boolean) {
656
+ // if the underlying view has changed we need to reattach handlers to the new view
657
+ const viewTag = findNodeHandle(state.viewRef) as number;
658
+ const forceReattach = viewTag !== state.previousViewTag;
659
+
660
+ if (forceReattach || needsToReattach(preparedGesture, gesture)) {
661
+ validateDetectorChildren(state.viewRef);
662
+ dropHandlers(preparedGesture);
663
+ attachHandlers({
664
+ preparedGesture,
665
+ gestureConfig,
666
+ gesture,
667
+ webEventHandlersRef,
668
+ viewTag,
669
+ mountedRef,
670
+ });
671
+
672
+ state.previousViewTag = viewTag;
673
+ state.forceReattach = forceReattach;
674
+ if (forceReattach) {
675
+ forceRender();
676
+ }
677
+ } else if (!skipConfigUpdate) {
678
+ updateHandlers(preparedGesture, gestureConfig, gesture, mountedRef);
679
+ }
680
+ }
681
+
630
682
  // Reanimated event should be rebuilt only when gestures are reattached, otherwise
631
683
  // config update will be enough as all necessary items are stored in shared values anyway
632
684
  const needsToRebuildReanimatedEvent =
633
- preparedGesture.firstExecution || needsToReattach(preparedGesture, gesture);
685
+ preparedGesture.firstExecution ||
686
+ needsToReattach(preparedGesture, gesture) ||
687
+ state.forceReattach;
688
+
689
+ state.forceReattach = false;
634
690
 
635
691
  if (preparedGesture.firstExecution) {
636
692
  gestureConfig.initialize();
@@ -643,17 +699,19 @@ export const GestureDetector = (props: GestureDetectorProps) => {
643
699
  }
644
700
 
645
701
  useEffect(() => {
646
- firstRenderRef.current = true;
702
+ const viewTag = findNodeHandle(state.viewRef) as number;
703
+ state.firstRender = true;
647
704
  mountedRef.current = true;
648
- const viewTag = findNodeHandle(viewRef.current) as number;
649
705
 
650
- validateDetectorChildren(viewRef.current);
706
+ validateDetectorChildren(state.viewRef);
707
+
651
708
  attachHandlers({
652
709
  preparedGesture,
653
710
  gestureConfig,
654
711
  gesture,
655
- viewTag,
656
712
  webEventHandlersRef,
713
+ viewTag,
714
+ mountedRef,
657
715
  });
658
716
 
659
717
  return () => {
@@ -663,31 +721,26 @@ export const GestureDetector = (props: GestureDetectorProps) => {
663
721
  }, []);
664
722
 
665
723
  useEffect(() => {
666
- if (!firstRenderRef.current) {
667
- const viewTag = findNodeHandle(viewRef.current) as number;
668
-
669
- if (needsToReattach(preparedGesture, gesture)) {
670
- validateDetectorChildren(viewRef.current);
671
- dropHandlers(preparedGesture);
672
- attachHandlers({
673
- preparedGesture,
674
- gestureConfig,
675
- gesture,
676
- viewTag,
677
- webEventHandlersRef,
678
- });
679
- } else {
680
- updateHandlers(preparedGesture, gestureConfig, gesture, mountedRef);
681
- }
724
+ if (!state.firstRender) {
725
+ onHandlersUpdate();
682
726
  } else {
683
- firstRenderRef.current = false;
727
+ state.firstRender = false;
684
728
  }
685
729
  }, [props]);
686
730
 
687
731
  const refFunction = (ref: unknown) => {
688
732
  if (ref !== null) {
689
- //@ts-ignore Just setting the ref
690
- viewRef.current = ref;
733
+ // @ts-ignore Just setting the view ref
734
+ state.viewRef = ref;
735
+
736
+ // if it's the first render, also set the previousViewTag to prevent reattaching gestures when not needed
737
+ if (state.previousViewTag === -1) {
738
+ state.previousViewTag = findNodeHandle(state.viewRef) as number;
739
+ }
740
+
741
+ // pass true as `skipConfigUpdate`, here we only want to trigger the eventual reattaching of handlers
742
+ // in case the view has changed, while config update would be handled be the `useEffect` above
743
+ onHandlersUpdate(true);
691
744
 
692
745
  if (isFabric()) {
693
746
  const node = getShadowNodeFromRef(ref);
@@ -11,6 +11,7 @@ export class LongPressGesture extends BaseGesture<LongPressGestureHandlerEventPa
11
11
  super();
12
12
 
13
13
  this.handlerName = 'LongPressGestureHandler';
14
+ this.shouldCancelWhenOutside(true);
14
15
  }
15
16
 
16
17
  minDuration(duration: number) {
@@ -11,6 +11,7 @@ export class TapGesture extends BaseGesture<TapGestureHandlerEventPayload> {
11
11
  super();
12
12
 
13
13
  this.handlerName = 'TapGestureHandler';
14
+ this.shouldCancelWhenOutside(true);
14
15
  }
15
16
 
16
17
  minPointers(minPointers: number) {
@@ -22,7 +22,6 @@ export default class LongPressGestureHandler extends GestureHandler {
22
22
 
23
23
  public init(ref: number, propsRef: React.RefObject<unknown>) {
24
24
  super.init(ref, propsRef);
25
- this.setShouldCancelWhenOutside(true);
26
25
 
27
26
  this.view.oncontextmenu = () => false;
28
27
  }
@@ -33,7 +33,6 @@ export default class TapGestureHandler extends GestureHandler {
33
33
 
34
34
  public init(ref: number, propsRef: React.RefObject<unknown>): void {
35
35
  super.init(ref, propsRef);
36
- this.setShouldCancelWhenOutside(true);
37
36
  }
38
37
 
39
38
  public updateGestureConfig({ enabled = true, ...props }: Config): void {