Skip to content

Commit ee6107f

Browse files
authored
[Web] Separate Reanimated from JS (#3683)
## Description Web portion of functionality from PR #3682 > Currently we have 2 ways of handling events - Animated and JS/Reanimated. Handling both JS and Reanimated in the same places results in more complex codebase. It also introduces problems with composing gestures. We decided to spit those implementations. ## Test plan ```tsx import * as React from 'react'; import { Animated, Button } from 'react-native'; import { GestureHandlerRootView, NativeDetector, useGesture, } from 'react-native-gesture-handler'; export default function App() { const [visible, setVisible] = React.useState(true); const av = React.useRef(new Animated.Value(0)).current const event = Animated.event( [{ handlerData: { translationX: av } }], { useNativeDriver: false, } ); const gesture = useGesture('PanGestureHandler', { onBegin: (e: unknown) => { 'worklet'; console.log('onBegin', e); }, onStart: (e: unknown) => { 'worklet'; console.log('onStart', e); }, // onUpdate: event, onUpdate: (e: unknown) => { 'worklet'; console.log('onUpdate', e); }, onEnd: (e: unknown) => { 'worklet'; console.log('onEnd', e); }, onFinalize: (e: unknown) => { 'worklet'; console.log('onFinalize', e); }, onTouchesDown: (e: unknown) => { 'worklet'; console.log('onTouchesDown', e); }, onTouchesMove: (e: unknown) => { 'worklet'; console.log('onTouchesMoved', e); }, onTouchesUp: (e: unknown) => { 'worklet'; console.log('onTouchesUp', e); }, onTouchesCancelled: (e: unknown) => { 'worklet'; console.log('onTouchesCancelled', e); }, }); return ( <GestureHandlerRootView style={{ flex: 1, backgroundColor: 'white', paddingTop: 8 }}> <Button title="Toggle visibility" onPress={() => { setVisible(!visible); }} /> {visible && ( <NativeDetector gesture={gesture}> <Animated.View style={[ { width: 150, height: 150, backgroundColor: 'blue', opacity: 0.5, borderWidth: 10, borderColor: 'green', marginTop: 20, marginLeft: 40, }, { transform: [{ translateX: av }] }, ]} /> </NativeDetector> )} </GestureHandlerRootView> ); } ```
1 parent abccee8 commit ee6107f

File tree

3 files changed

+73
-25
lines changed

3 files changed

+73
-25
lines changed

packages/react-native-gesture-handler/src/handlers/gestures/GestureDetector/utils.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,5 +175,8 @@ export function useWebEventHandlers() {
175175
onGestureHandlerStateChange: (e: ResultEvent) => {
176176
onGestureHandlerEvent(e.nativeEvent as GestureHandlerNativeEvent);
177177
},
178+
onGestureHandlerTouchEvent: () => {
179+
// no-op
180+
},
178181
});
179182
}

packages/react-native-gesture-handler/src/web/handlers/GestureHandler.ts

Lines changed: 64 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ export default abstract class GestureHandler implements IGestureHandler {
4040
private viewRef: number | null = null;
4141
private propsRef: React.RefObject<PropsRef> | null = null;
4242
private actionType: ActionType | null = null;
43-
private dispatchesAnimatedEvents: boolean = false;
43+
private forAnimated: boolean = false;
44+
private forReanimated: boolean = false;
4445
private _handlerTag!: number;
4546

4647
private hitSlop?: HitSlop = undefined;
@@ -96,7 +97,8 @@ export default abstract class GestureHandler implements IGestureHandler {
9697
this.viewRef = null;
9798
this.actionType = null;
9899
this.state = State.UNDETERMINED;
99-
this.dispatchesAnimatedEvents = false;
100+
this.forAnimated = false;
101+
this.forReanimated = false;
100102

101103
this.delegate.detach();
102104
}
@@ -380,21 +382,28 @@ export default abstract class GestureHandler implements IGestureHandler {
380382
return;
381383
}
382384
this.ensurePropsRef();
383-
const { onGestureHandlerEvent, onGestureHandlerTouchEvent }: PropsRef =
384-
this.propsRef!.current;
385+
const {
386+
onGestureHandlerEvent,
387+
onGestureHandlerTouchEvent,
388+
onGestureHandlerReanimatedTouchEvent,
389+
}: PropsRef = this.propsRef!.current;
385390

386391
const touchEvent: ResultEvent<GestureTouchEvent> | undefined =
387392
this.transformTouchEvent(event);
388393

389-
if (touchEvent) {
390-
if (
391-
onGestureHandlerTouchEvent &&
392-
this.actionType === ActionType.NATIVE_DETECTOR
393-
) {
394-
invokeNullableMethod(onGestureHandlerTouchEvent, touchEvent);
395-
} else {
396-
invokeNullableMethod(onGestureHandlerEvent, touchEvent);
397-
}
394+
if (!touchEvent) {
395+
return;
396+
}
397+
398+
if (this.actionType === ActionType.NATIVE_DETECTOR) {
399+
invokeNullableMethod(
400+
this.forReanimated
401+
? onGestureHandlerReanimatedTouchEvent
402+
: onGestureHandlerTouchEvent,
403+
touchEvent
404+
);
405+
} else {
406+
invokeNullableMethod(onGestureHandlerEvent, touchEvent);
398407
}
399408
}
400409

@@ -407,6 +416,8 @@ export default abstract class GestureHandler implements IGestureHandler {
407416
onGestureHandlerEvent,
408417
onGestureHandlerStateChange,
409418
onGestureHandlerAnimatedEvent,
419+
onGestureHandlerReanimatedEvent,
420+
onGestureHandlerReanimatedStateChange,
410421
}: PropsRef = this.propsRef!.current;
411422
const resultEvent: ResultEvent =
412423
this.actionType !== ActionType.NATIVE_DETECTOR
@@ -422,17 +433,27 @@ export default abstract class GestureHandler implements IGestureHandler {
422433

423434
if (this.lastSentState !== newState) {
424435
this.lastSentState = newState;
425-
invokeNullableMethod(onGestureHandlerStateChange, resultEvent);
436+
invokeNullableMethod(
437+
this.forReanimated
438+
? onGestureHandlerReanimatedStateChange
439+
: onGestureHandlerStateChange,
440+
resultEvent
441+
);
426442
}
427443
if (this.state === State.ACTIVE) {
428444
if (this.actionType !== ActionType.NATIVE_DETECTOR) {
429445
(resultEvent.nativeEvent as GestureHandlerNativeEvent).oldState =
430446
undefined;
431447
}
432-
if (onGestureHandlerAnimatedEvent && this.dispatchesAnimatedEvents) {
433-
invokeNullableMethod(onGestureHandlerAnimatedEvent, resultEvent);
434-
}
435-
invokeNullableMethod(onGestureHandlerEvent, resultEvent);
448+
449+
invokeNullableMethod(
450+
this.forReanimated
451+
? onGestureHandlerReanimatedEvent
452+
: this.forAnimated
453+
? onGestureHandlerAnimatedEvent
454+
: onGestureHandlerEvent,
455+
resultEvent
456+
);
436457
}
437458
};
438459

@@ -637,9 +658,22 @@ export default abstract class GestureHandler implements IGestureHandler {
637658
timeStamp: Date.now(),
638659
};
639660

640-
const { onGestureHandlerEvent }: PropsRef = this.propsRef!.current;
661+
const {
662+
onGestureHandlerEvent,
663+
onGestureHandlerReanimatedTouchEvent,
664+
onGestureHandlerTouchEvent,
665+
}: PropsRef = this.propsRef!.current;
641666

642-
invokeNullableMethod(onGestureHandlerEvent, cancelEvent);
667+
if (this.actionType === ActionType.NATIVE_DETECTOR) {
668+
invokeNullableMethod(
669+
this.forReanimated
670+
? onGestureHandlerReanimatedTouchEvent
671+
: onGestureHandlerTouchEvent,
672+
cancelEvent
673+
);
674+
} else {
675+
invokeNullableMethod(onGestureHandlerEvent, cancelEvent);
676+
}
643677
}
644678

645679
private ensurePropsRef(): void {
@@ -691,7 +725,11 @@ export default abstract class GestureHandler implements IGestureHandler {
691725
}
692726

693727
if (config.dispatchesAnimatedEvents !== undefined) {
694-
this.dispatchesAnimatedEvents = config.dispatchesAnimatedEvents;
728+
this.forAnimated = config.dispatchesAnimatedEvents;
729+
}
730+
731+
if (config.shouldUseReanimated !== undefined) {
732+
this.forReanimated = config.shouldUseReanimated;
695733
}
696734

697735
if (config.manualActivation !== undefined) {
@@ -874,7 +912,8 @@ export default abstract class GestureHandler implements IGestureHandler {
874912
this.mouseButton = undefined;
875913
this.hitSlop = undefined;
876914
this.needsPointerData = false;
877-
this.dispatchesAnimatedEvents = false;
915+
this.forAnimated = false;
916+
this.forReanimated = false;
878917
this.enableContextMenu = false;
879918
this._activeCursor = undefined;
880919
this._touchAction = undefined;
@@ -991,7 +1030,9 @@ function invokeNullableMethod(
9911030
method:
9921031
| ((event: ResultEvent) => void)
9931032
| { __getHandler: () => (event: ResultEvent) => void }
994-
| { __nodeConfig: { argMapping: unknown[] } },
1033+
| { __nodeConfig: { argMapping: unknown[] } }
1034+
| null
1035+
| undefined,
9951036
event: ResultEvent
9961037
): void {
9971038
if (!method) {

packages/react-native-gesture-handler/src/web/interfaces.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ export interface Config extends Record<string, ConfigArgs> {
5252
touchAction?: TouchAction;
5353
manualActivation?: boolean;
5454
dispatchesAnimatedEvents?: false;
55+
shouldUseReanimated?: boolean;
5556
needsPointerData?: false;
5657

5758
activateAfterLongPress?: number;
@@ -124,9 +125,12 @@ export interface ResultEvent<T extends ResultEventType = ResultEventType>
124125

125126
export interface PropsRef {
126127
onGestureHandlerEvent: (e: ResultEvent) => void;
127-
onGestureHandlerAnimatedEvent?: (e: ResultEvent) => void;
128128
onGestureHandlerStateChange: (e: ResultEvent) => void;
129-
onGestureHandlerTouchEvent?: (e: ResultEvent) => void;
129+
onGestureHandlerTouchEvent: (e: ResultEvent) => void;
130+
onGestureHandlerReanimatedEvent?: (e: ResultEvent) => void;
131+
onGestureHandlerReanimatedStateChange?: (e: ResultEvent) => void;
132+
onGestureHandlerReanimatedTouchEvent?: (e: ResultEvent) => void;
133+
onGestureHandlerAnimatedEvent?: (e: ResultEvent) => void;
130134
}
131135

132136
export interface AdaptedEvent {

0 commit comments

Comments
 (0)