react-native-gesture-handler 2.8.0 → 2.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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 {