From b87eb2bb45e589e271f74a7941fa4b35c9fe41cf Mon Sep 17 00:00:00 2001 From: Jakub Piasecki Date: Wed, 22 May 2024 12:32:26 +0200 Subject: [PATCH] Fix GestureDetector not working when its children change (#2921) ## Description On web `findNodeHandle` was returning the ref it received as an argument, which in the case of GestureDetector was a reference to the Wrap component. This worked fine until the children of the wrap changed (but the wrap itself didn't, which caused the handlers not to be reattached), in which case the new view didn't have event listeners added and gestures didn't work. This PR changes the used method to always call `findNodeHandle` which returns the reference to the underlying DOM element, and view change detection works correctly in this case. ## Test plan
Tested on the example app and on the following code: ```jsx import React, { useState } from 'react'; import { Button, StyleSheet, View } from 'react-native'; import { GestureDetector, Gesture } from 'react-native-gesture-handler'; import Animated, { useSharedValue, useAnimatedStyle, withSpring, } from 'react-native-reanimated'; function Ball(props) { const isPressed = useSharedValue(false); const offset = useSharedValue({ x: 0, y: 0 }); const animatedStyles = useAnimatedStyle(() => { return { transform: [ { translateX: offset.value.x }, { translateY: offset.value.y }, { scale: withSpring(isPressed.value ? 1.2 : 1) }, ], backgroundColor: isPressed.value ? 'yellow' : 'blue', }; }); const gesture = Gesture.Pan() .onBegin(() => { 'worklet'; isPressed.value = true; }) .onChange((e) => { 'worklet'; offset.value = { x: e.changeX + offset.value.x, y: e.changeY + offset.value.y, }; }) .onFinalize(() => { 'worklet'; isPressed.value = false; }); return ( ); } export default function Example() { const [counter, setCounter] = useState(0); return (
--- src/handlers/gestures/GestureDetector/index.tsx | 8 ++------ .../gestures/GestureDetector/useDetectorUpdater.ts | 2 +- .../gestures/GestureDetector/useViewRefHandler.ts | 3 +-- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/handlers/gestures/GestureDetector/index.tsx b/src/handlers/gestures/GestureDetector/index.tsx index 18f5ef8827..0f57b9c1ee 100644 --- a/src/handlers/gestures/GestureDetector/index.tsx +++ b/src/handlers/gestures/GestureDetector/index.tsx @@ -1,14 +1,10 @@ /* eslint-disable react/no-unused-prop-types */ import React, { useContext, useEffect, useMemo, useRef } from 'react'; +import { Platform, findNodeHandle } from 'react-native'; import { GestureType } from '../gesture'; -import { - findNodeHandle, - UserSelect, - TouchAction, -} from '../../gestureHandlerCommon'; +import { UserSelect, TouchAction } from '../../gestureHandlerCommon'; import { ComposedGesture } from '../gestureComposition'; import { isJestEnv } from '../../../utils'; -import { Platform } from 'react-native'; import GestureHandlerRootViewContext from '../../../GestureHandlerRootViewContext'; import { AttachedGestureState, GestureDetectorState } from './types'; diff --git a/src/handlers/gestures/GestureDetector/useDetectorUpdater.ts b/src/handlers/gestures/GestureDetector/useDetectorUpdater.ts index dbbb362ddd..0d6c0d7b2d 100644 --- a/src/handlers/gestures/GestureDetector/useDetectorUpdater.ts +++ b/src/handlers/gestures/GestureDetector/useDetectorUpdater.ts @@ -1,6 +1,6 @@ import React, { useCallback } from 'react'; +import { findNodeHandle } from 'react-native'; import { GestureType } from '../gesture'; -import { findNodeHandle } from '../../gestureHandlerCommon'; import { ComposedGesture } from '../gestureComposition'; import { diff --git a/src/handlers/gestures/GestureDetector/useViewRefHandler.ts b/src/handlers/gestures/GestureDetector/useViewRefHandler.ts index 1c1ebee0d4..258d216ba9 100644 --- a/src/handlers/gestures/GestureDetector/useViewRefHandler.ts +++ b/src/handlers/gestures/GestureDetector/useViewRefHandler.ts @@ -1,10 +1,9 @@ -import { findNodeHandle } from '../../gestureHandlerCommon'; - import { isFabric, tagMessage } from '../../../utils'; import { getShadowNodeFromRef } from '../../../getShadowNodeFromRef'; import { GestureDetectorState } from './types'; import React, { useCallback } from 'react'; +import { findNodeHandle } from 'react-native'; declare const global: { isFormsStackingContext: (node: unknown) => boolean | null; // JSI function