From 1c4ae0dc4409f4b6128ea790ae237f011c7a434f Mon Sep 17 00:00:00 2001 From: Jakub Piasecki Date: Thu, 18 Dec 2025 11:10:17 +0100 Subject: [PATCH 1/4] Reduce number of times the same callback is passed under different names --- .../src/jestUtils/jestUtils.ts | 2 +- .../src/v3/detectors/NativeDetector.tsx | 32 ++++++++-- .../InterceptingGestureDetector.tsx | 59 +++++++++++-------- .../hooks/composition/useComposedGesture.ts | 47 ++------------- .../src/v3/hooks/useGesture.ts | 29 ++------- .../src/v3/hooks/useGestureCallbacks.ts | 6 +- .../src/v3/types/DetectorTypes.ts | 18 ++---- 7 files changed, 79 insertions(+), 114 deletions(-) diff --git a/packages/react-native-gesture-handler/src/jestUtils/jestUtils.ts b/packages/react-native-gesture-handler/src/jestUtils/jestUtils.ts index ee7a951c57..40ef2c191d 100644 --- a/packages/react-native-gesture-handler/src/jestUtils/jestUtils.ts +++ b/packages/react-native-gesture-handler/src/jestUtils/jestUtils.ts @@ -445,7 +445,7 @@ function getHandlerData( }; if (eventName === 'onGestureHandlerStateChange') { - componentOrGesture.detectorCallbacks.onGestureHandlerStateChange({ + componentOrGesture.detectorCallbacks.onGestureHandlerEvent?.({ oldState: oldState as State, ...event, }); diff --git a/packages/react-native-gesture-handler/src/v3/detectors/NativeDetector.tsx b/packages/react-native-gesture-handler/src/v3/detectors/NativeDetector.tsx index 249da97d7e..d0cee29ec2 100644 --- a/packages/react-native-gesture-handler/src/v3/detectors/NativeDetector.tsx +++ b/packages/react-native-gesture-handler/src/v3/detectors/NativeDetector.tsx @@ -8,6 +8,7 @@ import { nativeDetectorStyles, } from './common'; import { ReanimatedNativeDetector } from './ReanimatedNativeDetector'; +import { Platform } from 'react-native'; export function NativeDetector({ gesture, @@ -29,6 +30,27 @@ export function NativeDetector({ return isComposedGesture(gesture) ? gesture.tags : [gesture.tag]; }, [gesture]); + // On web, we're triggering Reanimated callbacks ourselves, based on the type. + // To handle this properly, we need to provide all three callbacks, so we set + // all three to the Reanimated event handler. + // On native, Reanimated handles routing internally based on the event names + // passed to the useEvent hook. We only need to pass it once, so that Reanimated + // can setup its internal listeners. + const reanimatedHandlers = + Platform.OS === 'web' + ? { + onGestureHandlerReanimatedEvent: + gesture.detectorCallbacks.onGestureHandlerReanimatedEvent, + onGestureHandlerReanimatedStateChange: + gesture.detectorCallbacks.onGestureHandlerReanimatedEvent, + onGestureHandlerReanimatedTouchEvent: + gesture.detectorCallbacks.onGestureHandlerReanimatedEvent, + } + : { + onGestureHandlerReanimatedEvent: + gesture.detectorCallbacks.onGestureHandlerReanimatedEvent, + }; + return ( ({ pointerEvents={'box-none'} // @ts-ignore This is a type mismatch between RNGH types and RN Codegen types onGestureHandlerStateChange={ - gesture.detectorCallbacks.onGestureHandlerStateChange + gesture.detectorCallbacks.onGestureHandlerEvent } // @ts-ignore This is a type mismatch between RNGH types and RN Codegen types onGestureHandlerEvent={gesture.detectorCallbacks.onGestureHandlerEvent} // @ts-ignore This is a type mismatch between RNGH types and RN Codegen types onGestureHandlerTouchEvent={ - gesture.detectorCallbacks.onGestureHandlerTouchEvent + gesture.detectorCallbacks.onGestureHandlerEvent } // @ts-ignore This is a type mismatch between RNGH types and RN Codegen types onGestureHandlerReanimatedStateChange={ - gesture.detectorCallbacks.onReanimatedStateChange + reanimatedHandlers.onGestureHandlerReanimatedStateChange } // @ts-ignore This is a type mismatch between RNGH types and RN Codegen types onGestureHandlerReanimatedEvent={ - gesture.detectorCallbacks.onReanimatedUpdateEvent + reanimatedHandlers.onGestureHandlerReanimatedEvent } // @ts-ignore This is a type mismatch between RNGH types and RN Codegen types onGestureHandlerReanimatedTouchEvent={ - gesture.detectorCallbacks.onReanimatedTouchEvent + reanimatedHandlers.onGestureHandlerReanimatedTouchEvent } // @ts-ignore This is a type mismatch between RNGH types and RN Codegen types onGestureHandlerAnimatedEvent={ diff --git a/packages/react-native-gesture-handler/src/v3/detectors/VirtualDetector/InterceptingGestureDetector.tsx b/packages/react-native-gesture-handler/src/v3/detectors/VirtualDetector/InterceptingGestureDetector.tsx index 8b4fe6ad25..42bc8968f0 100644 --- a/packages/react-native-gesture-handler/src/v3/detectors/VirtualDetector/InterceptingGestureDetector.tsx +++ b/packages/react-native-gesture-handler/src/v3/detectors/VirtualDetector/InterceptingGestureDetector.tsx @@ -21,6 +21,7 @@ import { import { tagMessage } from '../../../utils'; import { useEnsureGestureHandlerRootView } from '../useEnsureGestureHandlerRootView'; import { ReanimatedNativeDetector } from '../ReanimatedNativeDetector'; +import { Platform } from 'react-native'; interface VirtualChildrenForNative { viewTag: number; @@ -176,29 +177,12 @@ export function InterceptingGestureDetector({ [virtualChildren, gesture?.detectorCallbacks] ); - const reanimatedUpdateEvents = useMemo( - () => getHandlers('onReanimatedUpdateEvent'), + const reanimatedEvents = useMemo( + () => getHandlers('onGestureHandlerReanimatedEvent'), [getHandlers] ); - const reanimatedEventHandler = Reanimated?.useComposedEventHandler( - reanimatedUpdateEvents - ); - - const reanimatedStateChangeEvents = useMemo( - () => getHandlers('onReanimatedStateChange'), - [getHandlers] - ); - const reanimatedStateChangeHandler = Reanimated?.useComposedEventHandler( - reanimatedStateChangeEvents - ); - - const reanimatedTouchEvents = useMemo( - () => getHandlers('onReanimatedTouchEvent'), - [getHandlers] - ); - const reanimatedTouchEventHandler = Reanimated?.useComposedEventHandler( - reanimatedTouchEvents - ); + const reanimatedEventHandler = + Reanimated?.useComposedEventHandler(reanimatedEvents); ensureNativeDetectorComponent(NativeDetectorComponent); @@ -213,13 +197,30 @@ export function InterceptingGestureDetector({ return []; }, [gesture]); + // On web, we're triggering Reanimated callbacks ourselves, based on the type. + // To handle this properly, we need to provide all three callbacks, so we set + // all three to the Reanimated event handler. + // On native, Reanimated handles routing internally based on the event names + // passed to the useEvent hook. We only need to pass it once, so that Reanimated + // can setup its internal listeners. + const reanimatedHandlers = + Platform.OS === 'web' + ? { + onGestureHandlerReanimatedEvent: reanimatedEventHandler, + onGestureHandlerReanimatedStateChange: reanimatedEventHandler, + onGestureHandlerReanimatedTouchEvent: reanimatedEventHandler, + } + : { + onGestureHandlerReanimatedEvent: reanimatedEventHandler, + }; + return ( createGestureEventHandler('onGestureHandlerStateChange'), + () => createGestureEventHandler('onGestureHandlerEvent'), [createGestureEventHandler] )} // @ts-ignore This is a type mismatch between RNGH types and RN Codegen types @@ -233,20 +234,26 @@ export function InterceptingGestureDetector({ } // @ts-ignore This is a type mismatch between RNGH types and RN Codegen types onGestureHandlerTouchEvent={useMemo( - () => createGestureEventHandler('onGestureHandlerTouchEvent'), + () => createGestureEventHandler('onGestureHandlerEvent'), [createGestureEventHandler] )} // @ts-ignore This is a type mismatch between RNGH types and RN Codegen types onGestureHandlerReanimatedStateChange={ - shouldUseReanimatedDetector ? reanimatedStateChangeHandler : undefined + shouldUseReanimatedDetector + ? reanimatedHandlers.onGestureHandlerReanimatedStateChange + : undefined } // @ts-ignore This is a type mismatch between RNGH types and RN Codegen types onGestureHandlerReanimatedEvent={ - shouldUseReanimatedDetector ? reanimatedEventHandler : undefined + shouldUseReanimatedDetector + ? reanimatedHandlers.onGestureHandlerReanimatedEvent + : undefined } // @ts-ignore This is a type mismatch between RNGH types and RN Codegen types onGestureHandlerReanimatedTouchEvent={ - shouldUseReanimatedDetector ? reanimatedTouchEventHandler : undefined + shouldUseReanimatedDetector + ? reanimatedHandlers.onGestureHandlerReanimatedTouchEvent + : undefined } handlerTags={handlerTags} style={nativeDetectorStyles.detector} diff --git a/packages/react-native-gesture-handler/src/v3/hooks/composition/useComposedGesture.ts b/packages/react-native-gesture-handler/src/v3/hooks/composition/useComposedGesture.ts index ad2280808d..1d5623d6fa 100644 --- a/packages/react-native-gesture-handler/src/v3/hooks/composition/useComposedGesture.ts +++ b/packages/react-native-gesture-handler/src/v3/hooks/composition/useComposedGesture.ts @@ -1,11 +1,9 @@ import { - StateChangeEventWithHandlerData, - UpdateEventWithHandlerData, - TouchEvent, ComposedGesture, ComposedGestureName, AnyGesture, ComposedGestureConfig, + GestureHandlerEventWithHandlerData, } from '../../types'; import { tagMessage } from '../../../utils'; import { Reanimated } from '../../../handlers/gestures/reanimatedWrapper'; @@ -45,18 +43,8 @@ export function useComposedGesture( ); } - const onGestureHandlerStateChange = ( - event: StateChangeEventWithHandlerData - ) => { - for (const gesture of gestures) { - if (gesture.detectorCallbacks.onGestureHandlerStateChange) { - gesture.detectorCallbacks.onGestureHandlerStateChange(event); - } - } - }; - const onGestureHandlerEvent = ( - event: UpdateEventWithHandlerData + event: GestureHandlerEventWithHandlerData ) => { for (const gesture of gestures) { if (gesture.detectorCallbacks.onGestureHandlerEvent) { @@ -65,29 +53,10 @@ export function useComposedGesture( } }; - const onGestureHandlerTouchEvent = (event: TouchEvent) => { - for (const gesture of gestures) { - if (gesture.detectorCallbacks.onGestureHandlerTouchEvent) { - gesture.detectorCallbacks.onGestureHandlerTouchEvent(event); - } - } - }; - - const onReanimatedStateChange = Reanimated?.useComposedEventHandler( - gestures.map( - (gesture) => gesture.detectorCallbacks.onReanimatedStateChange || null - ) - ); - - const onReanimatedUpdateEvent = Reanimated?.useComposedEventHandler( - gestures.map( - (gesture) => gesture.detectorCallbacks.onReanimatedUpdateEvent || null - ) - ); - - const onReanimatedTouchEvent = Reanimated?.useComposedEventHandler( + const onGestureHandlerReanimatedEvent = Reanimated?.useComposedEventHandler( gestures.map( - (gesture) => gesture.detectorCallbacks.onReanimatedTouchEvent || null + (gesture) => + gesture.detectorCallbacks.onGestureHandlerReanimatedEvent || null ) ); @@ -117,12 +86,8 @@ export function useComposedGesture( type, config, detectorCallbacks: { - onGestureHandlerStateChange, onGestureHandlerEvent, - onGestureHandlerTouchEvent, - onReanimatedStateChange, - onReanimatedUpdateEvent, - onReanimatedTouchEvent, + onGestureHandlerReanimatedEvent, onGestureHandlerAnimatedEvent, }, externalSimultaneousHandlers: [], diff --git a/packages/react-native-gesture-handler/src/v3/hooks/useGesture.ts b/packages/react-native-gesture-handler/src/v3/hooks/useGesture.ts index 98b49879a8..f23d02bd24 100644 --- a/packages/react-native-gesture-handler/src/v3/hooks/useGesture.ts +++ b/packages/react-native-gesture-handler/src/v3/hooks/useGesture.ts @@ -15,7 +15,6 @@ import { registerGesture, unregisterGesture, } from '../../handlers/handlersRegistry'; -import { Platform } from 'react-native'; import { NativeProxy } from '../NativeProxy'; export function useGesture( @@ -39,11 +38,11 @@ export function useGesture( // TODO: Call only necessary hooks depending on which callbacks are defined (?) const { onGestureHandlerEvent, - onReanimatedEvent, + onGestureHandlerReanimatedEvent, onGestureHandlerAnimatedEvent, } = useGestureCallbacks(tag, config); - if (config.shouldUseReanimatedDetector && !onReanimatedEvent) { + if (config.shouldUseReanimatedDetector && !onGestureHandlerReanimatedEvent) { throw new Error(tagMessage('Failed to create reanimated event handlers.')); } @@ -75,27 +74,9 @@ export function useGesture( type, config, detectorCallbacks: { - onGestureHandlerStateChange: onGestureHandlerEvent, - onGestureHandlerEvent: onGestureHandlerEvent, - onGestureHandlerTouchEvent: onGestureHandlerEvent, + onGestureHandlerEvent, onGestureHandlerAnimatedEvent, - // On web, we're triggering Reanimated callbacks ourselves, based on the type. - // To handle this properly, we need to provide all three callbacks, so we set - // all three to the Reanimated event handler. - // On native, Reanimated handles routing internally based on the event names - // passed to the useEvent hook. We only need to pass it once, so that Reanimated - // can setup its internal listeners. - ...(Platform.OS === 'web' - ? { - onReanimatedUpdateEvent: onReanimatedEvent, - onReanimatedStateChange: onReanimatedEvent, - onReanimatedTouchEvent: onReanimatedEvent, - } - : { - onReanimatedUpdateEvent: onReanimatedEvent, - onReanimatedStateChange: undefined, - onReanimatedTouchEvent: undefined, - }), + onGestureHandlerReanimatedEvent, }, gestureRelations, }), @@ -104,7 +85,7 @@ export function useGesture( type, config, onGestureHandlerEvent, - onReanimatedEvent, + onGestureHandlerReanimatedEvent, onGestureHandlerAnimatedEvent, gestureRelations, ] diff --git a/packages/react-native-gesture-handler/src/v3/hooks/useGestureCallbacks.ts b/packages/react-native-gesture-handler/src/v3/hooks/useGestureCallbacks.ts index 4704b83999..2d13b45ea0 100644 --- a/packages/react-native-gesture-handler/src/v3/hooks/useGestureCallbacks.ts +++ b/packages/react-native-gesture-handler/src/v3/hooks/useGestureCallbacks.ts @@ -48,13 +48,13 @@ export function useGestureCallbacks( config ); - let onReanimatedEvent; + let onGestureHandlerReanimatedEvent; if (!config.disableReanimated) { // eslint-disable-next-line react-hooks/rules-of-hooks const reanimatedHandler = Reanimated?.useHandler(callbacks); // eslint-disable-next-line react-hooks/rules-of-hooks - onReanimatedEvent = useReanimatedEventHandler( + onGestureHandlerReanimatedEvent = useReanimatedEventHandler( handlerTag, callbacks, reanimatedHandler, @@ -82,7 +82,7 @@ export function useGestureCallbacks( return { onGestureHandlerEvent, - onReanimatedEvent, + onGestureHandlerReanimatedEvent, onGestureHandlerAnimatedEvent, }; } diff --git a/packages/react-native-gesture-handler/src/v3/types/DetectorTypes.ts b/packages/react-native-gesture-handler/src/v3/types/DetectorTypes.ts index 5b4da179af..afab124505 100644 --- a/packages/react-native-gesture-handler/src/v3/types/DetectorTypes.ts +++ b/packages/react-native-gesture-handler/src/v3/types/DetectorTypes.ts @@ -1,26 +1,16 @@ import { AnimatedEvent, - StateChangeEventWithHandlerData, - UpdateEventWithHandlerData, - TouchEvent, GestureUpdateEventWithHandlerData, + GestureHandlerEventWithHandlerData, } from './EventTypes'; export type DetectorCallbacks = { - onGestureHandlerStateChange: ( - event: StateChangeEventWithHandlerData - ) => void; onGestureHandlerEvent: | undefined - | ((event: UpdateEventWithHandlerData) => void); - onGestureHandlerTouchEvent: (event: TouchEvent) => void; - onReanimatedStateChange: + | ((event: GestureHandlerEventWithHandlerData) => void); + onGestureHandlerReanimatedEvent: | undefined - | ((event: StateChangeEventWithHandlerData) => void); - onReanimatedUpdateEvent: - | undefined - | ((event: UpdateEventWithHandlerData) => void); - onReanimatedTouchEvent: undefined | ((event: TouchEvent) => void); + | ((event: GestureHandlerEventWithHandlerData) => void); onGestureHandlerAnimatedEvent: | undefined | AnimatedEvent From 761144c7fab2b9e68d33f12bbdabd7c897cb7b9d Mon Sep 17 00:00:00 2001 From: Jakub Piasecki Date: Thu, 18 Dec 2025 11:27:21 +0100 Subject: [PATCH 2/4] Rename event handlers --- .../src/jestUtils/jestUtils.ts | 4 +-- .../src/v3/detectors/NativeDetector.tsx | 18 ++++++------- .../InterceptingGestureDetector.tsx | 10 +++---- .../hooks/composition/useComposedGesture.ts | 27 +++++++++---------- .../src/v3/hooks/useGesture.ts | 21 +++++++-------- .../src/v3/hooks/useGestureCallbacks.ts | 18 ++++++------- .../src/v3/types/DetectorTypes.ts | 6 ++--- 7 files changed, 48 insertions(+), 56 deletions(-) diff --git a/packages/react-native-gesture-handler/src/jestUtils/jestUtils.ts b/packages/react-native-gesture-handler/src/jestUtils/jestUtils.ts index 40ef2c191d..eefe956cae 100644 --- a/packages/react-native-gesture-handler/src/jestUtils/jestUtils.ts +++ b/packages/react-native-gesture-handler/src/jestUtils/jestUtils.ts @@ -445,12 +445,12 @@ function getHandlerData( }; if (eventName === 'onGestureHandlerStateChange') { - componentOrGesture.detectorCallbacks.onGestureHandlerEvent?.({ + componentOrGesture.detectorCallbacks.defaultEventHandler?.({ oldState: oldState as State, ...event, }); } else if (eventName === 'onGestureHandlerEvent') { - componentOrGesture.detectorCallbacks.onGestureHandlerEvent?.(event); + componentOrGesture.detectorCallbacks.defaultEventHandler?.(event); } }, }; diff --git a/packages/react-native-gesture-handler/src/v3/detectors/NativeDetector.tsx b/packages/react-native-gesture-handler/src/v3/detectors/NativeDetector.tsx index d0cee29ec2..69dcffd659 100644 --- a/packages/react-native-gesture-handler/src/v3/detectors/NativeDetector.tsx +++ b/packages/react-native-gesture-handler/src/v3/detectors/NativeDetector.tsx @@ -40,15 +40,15 @@ export function NativeDetector({ Platform.OS === 'web' ? { onGestureHandlerReanimatedEvent: - gesture.detectorCallbacks.onGestureHandlerReanimatedEvent, + gesture.detectorCallbacks.reanimatedEventHandler, onGestureHandlerReanimatedStateChange: - gesture.detectorCallbacks.onGestureHandlerReanimatedEvent, + gesture.detectorCallbacks.reanimatedEventHandler, onGestureHandlerReanimatedTouchEvent: - gesture.detectorCallbacks.onGestureHandlerReanimatedEvent, + gesture.detectorCallbacks.reanimatedEventHandler, } : { onGestureHandlerReanimatedEvent: - gesture.detectorCallbacks.onGestureHandlerReanimatedEvent, + gesture.detectorCallbacks.reanimatedEventHandler, }; return ( @@ -59,14 +59,12 @@ export function NativeDetector({ pointerEvents={'box-none'} // @ts-ignore This is a type mismatch between RNGH types and RN Codegen types onGestureHandlerStateChange={ - gesture.detectorCallbacks.onGestureHandlerEvent + gesture.detectorCallbacks.defaultEventHandler } // @ts-ignore This is a type mismatch between RNGH types and RN Codegen types - onGestureHandlerEvent={gesture.detectorCallbacks.onGestureHandlerEvent} + onGestureHandlerEvent={gesture.detectorCallbacks.defaultEventHandler} // @ts-ignore This is a type mismatch between RNGH types and RN Codegen types - onGestureHandlerTouchEvent={ - gesture.detectorCallbacks.onGestureHandlerEvent - } + onGestureHandlerTouchEvent={gesture.detectorCallbacks.defaultEventHandler} // @ts-ignore This is a type mismatch between RNGH types and RN Codegen types onGestureHandlerReanimatedStateChange={ reanimatedHandlers.onGestureHandlerReanimatedStateChange @@ -81,7 +79,7 @@ export function NativeDetector({ } // @ts-ignore This is a type mismatch between RNGH types and RN Codegen types onGestureHandlerAnimatedEvent={ - gesture.detectorCallbacks.onGestureHandlerAnimatedEvent + gesture.detectorCallbacks.animatedEventHandler } moduleId={globalThis._RNGH_MODULE_ID} handlerTags={handlerTags} diff --git a/packages/react-native-gesture-handler/src/v3/detectors/VirtualDetector/InterceptingGestureDetector.tsx b/packages/react-native-gesture-handler/src/v3/detectors/VirtualDetector/InterceptingGestureDetector.tsx index 42bc8968f0..83b86f880e 100644 --- a/packages/react-native-gesture-handler/src/v3/detectors/VirtualDetector/InterceptingGestureDetector.tsx +++ b/packages/react-native-gesture-handler/src/v3/detectors/VirtualDetector/InterceptingGestureDetector.tsx @@ -178,7 +178,7 @@ export function InterceptingGestureDetector({ ); const reanimatedEvents = useMemo( - () => getHandlers('onGestureHandlerReanimatedEvent'), + () => getHandlers('reanimatedEventHandler'), [getHandlers] ); const reanimatedEventHandler = @@ -220,21 +220,21 @@ export function InterceptingGestureDetector({ pointerEvents={'box-none'} // @ts-ignore This is a type mismatch between RNGH types and RN Codegen types onGestureHandlerStateChange={useMemo( - () => createGestureEventHandler('onGestureHandlerEvent'), + () => createGestureEventHandler('defaultEventHandler'), [createGestureEventHandler] )} // @ts-ignore This is a type mismatch between RNGH types and RN Codegen types onGestureHandlerEvent={useMemo( - () => createGestureEventHandler('onGestureHandlerEvent'), + () => createGestureEventHandler('defaultEventHandler'), [createGestureEventHandler] )} // @ts-ignore This is a type mismatch between RNGH types and RN Codegen types onGestureHandlerAnimatedEvent={ - gesture?.detectorCallbacks.onGestureHandlerAnimatedEvent + gesture?.detectorCallbacks.animatedEventHandler } // @ts-ignore This is a type mismatch between RNGH types and RN Codegen types onGestureHandlerTouchEvent={useMemo( - () => createGestureEventHandler('onGestureHandlerEvent'), + () => createGestureEventHandler('defaultEventHandler'), [createGestureEventHandler] )} // @ts-ignore This is a type mismatch between RNGH types and RN Codegen types diff --git a/packages/react-native-gesture-handler/src/v3/hooks/composition/useComposedGesture.ts b/packages/react-native-gesture-handler/src/v3/hooks/composition/useComposedGesture.ts index 1d5623d6fa..4e06ec9506 100644 --- a/packages/react-native-gesture-handler/src/v3/hooks/composition/useComposedGesture.ts +++ b/packages/react-native-gesture-handler/src/v3/hooks/composition/useComposedGesture.ts @@ -43,34 +43,31 @@ export function useComposedGesture( ); } - const onGestureHandlerEvent = ( + const defaultEventHandler = ( event: GestureHandlerEventWithHandlerData ) => { for (const gesture of gestures) { - if (gesture.detectorCallbacks.onGestureHandlerEvent) { - gesture.detectorCallbacks.onGestureHandlerEvent(event); + if (gesture.detectorCallbacks.defaultEventHandler) { + gesture.detectorCallbacks.defaultEventHandler(event); } } }; - const onGestureHandlerReanimatedEvent = Reanimated?.useComposedEventHandler( + const reanimatedEventHandler = Reanimated?.useComposedEventHandler( gestures.map( - (gesture) => - gesture.detectorCallbacks.onGestureHandlerReanimatedEvent || null + (gesture) => gesture.detectorCallbacks.reanimatedEventHandler || null ) ); - let onGestureHandlerAnimatedEvent; + let animatedEventHandler; const gesturesWithAnimatedEvent = gestures.filter( - (gesture) => - gesture.detectorCallbacks.onGestureHandlerAnimatedEvent !== undefined + (gesture) => gesture.detectorCallbacks.animatedEventHandler !== undefined ); if (gesturesWithAnimatedEvent.length > 0) { - onGestureHandlerAnimatedEvent = - gesturesWithAnimatedEvent[0].detectorCallbacks - .onGestureHandlerAnimatedEvent; + animatedEventHandler = + gesturesWithAnimatedEvent[0].detectorCallbacks.animatedEventHandler; if (__DEV__ && gesturesWithAnimatedEvent.length > 1) { console.warn( @@ -86,9 +83,9 @@ export function useComposedGesture( type, config, detectorCallbacks: { - onGestureHandlerEvent, - onGestureHandlerReanimatedEvent, - onGestureHandlerAnimatedEvent, + defaultEventHandler, + reanimatedEventHandler, + animatedEventHandler, }, externalSimultaneousHandlers: [], gestures, diff --git a/packages/react-native-gesture-handler/src/v3/hooks/useGesture.ts b/packages/react-native-gesture-handler/src/v3/hooks/useGesture.ts index f23d02bd24..0e54c3fed1 100644 --- a/packages/react-native-gesture-handler/src/v3/hooks/useGesture.ts +++ b/packages/react-native-gesture-handler/src/v3/hooks/useGesture.ts @@ -36,13 +36,10 @@ export function useGesture( prepareConfig(config); // TODO: Call only necessary hooks depending on which callbacks are defined (?) - const { - onGestureHandlerEvent, - onGestureHandlerReanimatedEvent, - onGestureHandlerAnimatedEvent, - } = useGestureCallbacks(tag, config); + const { defaultEventHandler, reanimatedEventHandler, animatedEventHandler } = + useGestureCallbacks(tag, config); - if (config.shouldUseReanimatedDetector && !onGestureHandlerReanimatedEvent) { + if (config.shouldUseReanimatedDetector && !reanimatedEventHandler) { throw new Error(tagMessage('Failed to create reanimated event handlers.')); } @@ -74,9 +71,9 @@ export function useGesture( type, config, detectorCallbacks: { - onGestureHandlerEvent, - onGestureHandlerAnimatedEvent, - onGestureHandlerReanimatedEvent, + defaultEventHandler, + animatedEventHandler, + reanimatedEventHandler, }, gestureRelations, }), @@ -84,9 +81,9 @@ export function useGesture( tag, type, config, - onGestureHandlerEvent, - onGestureHandlerReanimatedEvent, - onGestureHandlerAnimatedEvent, + defaultEventHandler, + reanimatedEventHandler, + animatedEventHandler, gestureRelations, ] ); diff --git a/packages/react-native-gesture-handler/src/v3/hooks/useGestureCallbacks.ts b/packages/react-native-gesture-handler/src/v3/hooks/useGestureCallbacks.ts index 2d13b45ea0..c5ce85a2c6 100644 --- a/packages/react-native-gesture-handler/src/v3/hooks/useGestureCallbacks.ts +++ b/packages/react-native-gesture-handler/src/v3/hooks/useGestureCallbacks.ts @@ -42,19 +42,19 @@ export function useGestureCallbacks( ) { const callbacks = useMemoizedGestureCallbacks(config); - const onGestureHandlerEvent = useGestureEventHandler( + const defaultEventHandler = useGestureEventHandler( handlerTag, callbacks, config ); - let onGestureHandlerReanimatedEvent; + let reanimatedEventHandler; if (!config.disableReanimated) { // eslint-disable-next-line react-hooks/rules-of-hooks const reanimatedHandler = Reanimated?.useHandler(callbacks); // eslint-disable-next-line react-hooks/rules-of-hooks - onGestureHandlerReanimatedEvent = useReanimatedEventHandler( + reanimatedEventHandler = useReanimatedEventHandler( handlerTag, callbacks, reanimatedHandler, @@ -62,7 +62,7 @@ export function useGestureCallbacks( ); } - let onGestureHandlerAnimatedEvent: + let animatedEventHandler: | ((event: GestureUpdateEventWithHandlerData) => void) | AnimatedEvent | undefined; @@ -73,16 +73,16 @@ export function useGestureCallbacks( if (__DEV__ && !isNativeAnimatedEvent(config.onUpdate)) { // @ts-expect-error At this point we know it's not a native animated event, so it's callable - onGestureHandlerAnimatedEvent = guardJSAnimatedEvent(config.onUpdate); + animatedEventHandler = guardJSAnimatedEvent(config.onUpdate); } else { // @ts-expect-error The structure of an AnimatedEvent differs from other event types - onGestureHandlerAnimatedEvent = config.onUpdate; + animatedEventHandler = config.onUpdate; } } return { - onGestureHandlerEvent, - onGestureHandlerReanimatedEvent, - onGestureHandlerAnimatedEvent, + defaultEventHandler, + reanimatedEventHandler, + animatedEventHandler, }; } diff --git a/packages/react-native-gesture-handler/src/v3/types/DetectorTypes.ts b/packages/react-native-gesture-handler/src/v3/types/DetectorTypes.ts index afab124505..dd6d1bfa21 100644 --- a/packages/react-native-gesture-handler/src/v3/types/DetectorTypes.ts +++ b/packages/react-native-gesture-handler/src/v3/types/DetectorTypes.ts @@ -5,13 +5,13 @@ import { } from './EventTypes'; export type DetectorCallbacks = { - onGestureHandlerEvent: + defaultEventHandler: | undefined | ((event: GestureHandlerEventWithHandlerData) => void); - onGestureHandlerReanimatedEvent: + reanimatedEventHandler: | undefined | ((event: GestureHandlerEventWithHandlerData) => void); - onGestureHandlerAnimatedEvent: + animatedEventHandler: | undefined | AnimatedEvent | ((event: GestureUpdateEventWithHandlerData) => void); From 0a235228bd972720e7e8e2742261f46881ba62ca Mon Sep 17 00:00:00 2001 From: Jakub Piasecki Date: Thu, 18 Dec 2025 11:28:31 +0100 Subject: [PATCH 3/4] Memoize callback once --- .../InterceptingGestureDetector.tsx | 22 ++++++++----------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/packages/react-native-gesture-handler/src/v3/detectors/VirtualDetector/InterceptingGestureDetector.tsx b/packages/react-native-gesture-handler/src/v3/detectors/VirtualDetector/InterceptingGestureDetector.tsx index 83b86f880e..b77ce69789 100644 --- a/packages/react-native-gesture-handler/src/v3/detectors/VirtualDetector/InterceptingGestureDetector.tsx +++ b/packages/react-native-gesture-handler/src/v3/detectors/VirtualDetector/InterceptingGestureDetector.tsx @@ -214,30 +214,26 @@ export function InterceptingGestureDetector({ onGestureHandlerReanimatedEvent: reanimatedEventHandler, }; + const jsEventHandler = useMemo( + () => createGestureEventHandler('defaultEventHandler'), + [createGestureEventHandler] + ); + return ( createGestureEventHandler('defaultEventHandler'), - [createGestureEventHandler] - )} + onGestureHandlerStateChange={jsEventHandler} // @ts-ignore This is a type mismatch between RNGH types and RN Codegen types - onGestureHandlerEvent={useMemo( - () => createGestureEventHandler('defaultEventHandler'), - [createGestureEventHandler] - )} + onGestureHandlerEvent={jsEventHandler} + // @ts-ignore This is a type mismatch between RNGH types and RN Codegen types + onGestureHandlerTouchEvent={jsEventHandler} // @ts-ignore This is a type mismatch between RNGH types and RN Codegen types onGestureHandlerAnimatedEvent={ gesture?.detectorCallbacks.animatedEventHandler } // @ts-ignore This is a type mismatch between RNGH types and RN Codegen types - onGestureHandlerTouchEvent={useMemo( - () => createGestureEventHandler('defaultEventHandler'), - [createGestureEventHandler] - )} - // @ts-ignore This is a type mismatch between RNGH types and RN Codegen types onGestureHandlerReanimatedStateChange={ shouldUseReanimatedDetector ? reanimatedHandlers.onGestureHandlerReanimatedStateChange From fcd7059b444813690d81c888cf9b282176f4997b Mon Sep 17 00:00:00 2001 From: Jakub Piasecki Date: Thu, 18 Dec 2025 11:34:52 +0100 Subject: [PATCH 4/4] Rename again --- .../src/jestUtils/jestUtils.ts | 4 ++-- .../src/v3/detectors/NativeDetector.tsx | 8 +++----- .../VirtualDetector/InterceptingGestureDetector.tsx | 2 +- .../src/v3/hooks/composition/useComposedGesture.ts | 8 ++++---- .../src/v3/hooks/useGesture.ts | 6 +++--- .../src/v3/hooks/useGestureCallbacks.ts | 8 ++------ .../src/v3/types/DetectorTypes.ts | 2 +- 7 files changed, 16 insertions(+), 22 deletions(-) diff --git a/packages/react-native-gesture-handler/src/jestUtils/jestUtils.ts b/packages/react-native-gesture-handler/src/jestUtils/jestUtils.ts index eefe956cae..2da89dee03 100644 --- a/packages/react-native-gesture-handler/src/jestUtils/jestUtils.ts +++ b/packages/react-native-gesture-handler/src/jestUtils/jestUtils.ts @@ -445,12 +445,12 @@ function getHandlerData( }; if (eventName === 'onGestureHandlerStateChange') { - componentOrGesture.detectorCallbacks.defaultEventHandler?.({ + componentOrGesture.detectorCallbacks.jsEventHandler?.({ oldState: oldState as State, ...event, }); } else if (eventName === 'onGestureHandlerEvent') { - componentOrGesture.detectorCallbacks.defaultEventHandler?.(event); + componentOrGesture.detectorCallbacks.jsEventHandler?.(event); } }, }; diff --git a/packages/react-native-gesture-handler/src/v3/detectors/NativeDetector.tsx b/packages/react-native-gesture-handler/src/v3/detectors/NativeDetector.tsx index 69dcffd659..a866b96752 100644 --- a/packages/react-native-gesture-handler/src/v3/detectors/NativeDetector.tsx +++ b/packages/react-native-gesture-handler/src/v3/detectors/NativeDetector.tsx @@ -58,13 +58,11 @@ export function NativeDetector({ enableContextMenu={enableContextMenu} pointerEvents={'box-none'} // @ts-ignore This is a type mismatch between RNGH types and RN Codegen types - onGestureHandlerStateChange={ - gesture.detectorCallbacks.defaultEventHandler - } + onGestureHandlerStateChange={gesture.detectorCallbacks.jsEventHandler} // @ts-ignore This is a type mismatch between RNGH types and RN Codegen types - onGestureHandlerEvent={gesture.detectorCallbacks.defaultEventHandler} + onGestureHandlerEvent={gesture.detectorCallbacks.jsEventHandler} // @ts-ignore This is a type mismatch between RNGH types and RN Codegen types - onGestureHandlerTouchEvent={gesture.detectorCallbacks.defaultEventHandler} + onGestureHandlerTouchEvent={gesture.detectorCallbacks.jsEventHandler} // @ts-ignore This is a type mismatch between RNGH types and RN Codegen types onGestureHandlerReanimatedStateChange={ reanimatedHandlers.onGestureHandlerReanimatedStateChange diff --git a/packages/react-native-gesture-handler/src/v3/detectors/VirtualDetector/InterceptingGestureDetector.tsx b/packages/react-native-gesture-handler/src/v3/detectors/VirtualDetector/InterceptingGestureDetector.tsx index b77ce69789..ba99ef5e67 100644 --- a/packages/react-native-gesture-handler/src/v3/detectors/VirtualDetector/InterceptingGestureDetector.tsx +++ b/packages/react-native-gesture-handler/src/v3/detectors/VirtualDetector/InterceptingGestureDetector.tsx @@ -215,7 +215,7 @@ export function InterceptingGestureDetector({ }; const jsEventHandler = useMemo( - () => createGestureEventHandler('defaultEventHandler'), + () => createGestureEventHandler('jsEventHandler'), [createGestureEventHandler] ); diff --git a/packages/react-native-gesture-handler/src/v3/hooks/composition/useComposedGesture.ts b/packages/react-native-gesture-handler/src/v3/hooks/composition/useComposedGesture.ts index 4e06ec9506..189dbf40e5 100644 --- a/packages/react-native-gesture-handler/src/v3/hooks/composition/useComposedGesture.ts +++ b/packages/react-native-gesture-handler/src/v3/hooks/composition/useComposedGesture.ts @@ -43,12 +43,12 @@ export function useComposedGesture( ); } - const defaultEventHandler = ( + const jsEventHandler = ( event: GestureHandlerEventWithHandlerData ) => { for (const gesture of gestures) { - if (gesture.detectorCallbacks.defaultEventHandler) { - gesture.detectorCallbacks.defaultEventHandler(event); + if (gesture.detectorCallbacks.jsEventHandler) { + gesture.detectorCallbacks.jsEventHandler(event); } } }; @@ -83,7 +83,7 @@ export function useComposedGesture( type, config, detectorCallbacks: { - defaultEventHandler, + jsEventHandler, reanimatedEventHandler, animatedEventHandler, }, diff --git a/packages/react-native-gesture-handler/src/v3/hooks/useGesture.ts b/packages/react-native-gesture-handler/src/v3/hooks/useGesture.ts index 0e54c3fed1..196c2d2777 100644 --- a/packages/react-native-gesture-handler/src/v3/hooks/useGesture.ts +++ b/packages/react-native-gesture-handler/src/v3/hooks/useGesture.ts @@ -36,7 +36,7 @@ export function useGesture( prepareConfig(config); // TODO: Call only necessary hooks depending on which callbacks are defined (?) - const { defaultEventHandler, reanimatedEventHandler, animatedEventHandler } = + const { jsEventHandler, reanimatedEventHandler, animatedEventHandler } = useGestureCallbacks(tag, config); if (config.shouldUseReanimatedDetector && !reanimatedEventHandler) { @@ -71,7 +71,7 @@ export function useGesture( type, config, detectorCallbacks: { - defaultEventHandler, + jsEventHandler, animatedEventHandler, reanimatedEventHandler, }, @@ -81,7 +81,7 @@ export function useGesture( tag, type, config, - defaultEventHandler, + jsEventHandler, reanimatedEventHandler, animatedEventHandler, gestureRelations, diff --git a/packages/react-native-gesture-handler/src/v3/hooks/useGestureCallbacks.ts b/packages/react-native-gesture-handler/src/v3/hooks/useGestureCallbacks.ts index c5ce85a2c6..1f1bb70804 100644 --- a/packages/react-native-gesture-handler/src/v3/hooks/useGestureCallbacks.ts +++ b/packages/react-native-gesture-handler/src/v3/hooks/useGestureCallbacks.ts @@ -42,11 +42,7 @@ export function useGestureCallbacks( ) { const callbacks = useMemoizedGestureCallbacks(config); - const defaultEventHandler = useGestureEventHandler( - handlerTag, - callbacks, - config - ); + const jsEventHandler = useGestureEventHandler(handlerTag, callbacks, config); let reanimatedEventHandler; @@ -81,7 +77,7 @@ export function useGestureCallbacks( } return { - defaultEventHandler, + jsEventHandler, reanimatedEventHandler, animatedEventHandler, }; diff --git a/packages/react-native-gesture-handler/src/v3/types/DetectorTypes.ts b/packages/react-native-gesture-handler/src/v3/types/DetectorTypes.ts index dd6d1bfa21..dca181be8d 100644 --- a/packages/react-native-gesture-handler/src/v3/types/DetectorTypes.ts +++ b/packages/react-native-gesture-handler/src/v3/types/DetectorTypes.ts @@ -5,7 +5,7 @@ import { } from './EventTypes'; export type DetectorCallbacks = { - defaultEventHandler: + jsEventHandler: | undefined | ((event: GestureHandlerEventWithHandlerData) => void); reanimatedEventHandler: