Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,16 @@ class RNGestureHandlerModule(reactContext: ReactApplicationContext?) :
}

@ReactMethod
override fun createGestureHandler(handlerName: String, handlerTagDouble: Double, config: ReadableMap) {
override fun createGestureHandler(handlerName: String, handlerTagDouble: Double, config: ReadableMap): Boolean {
if (ReanimatedProxy.REANIMATED_INSTALLED && !uiRuntimeDecorated) {
uiRuntimeDecorated = decorateUIRuntime()
}

val handlerTag = handlerTagDouble.toInt()

createGestureHandlerHelper<GestureHandler>(handlerName, handlerTag, config)

return true
}

@ReactMethod
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ - (bool)installUIRuntimeBindings
});
}

- (void)createGestureHandler:(NSString *)handlerName handlerTag:(double)handlerTag config:(NSDictionary *)config
- (NSNumber *)createGestureHandler:(NSString *)handlerName handlerTag:(double)handlerTag config:(NSDictionary *)config
{
if (!_checkedIfReanimatedIsAvailable) {
_isReanimatedAvailable = [self.moduleRegistry moduleForName:"ReanimatedModule"] != nil;
Expand All @@ -129,9 +129,10 @@ - (void)createGestureHandler:(NSString *)handlerName handlerTag:(double)handlerT
_uiRuntimeDecorated = [self installUIRuntimeBindings];
}

[self addOperationBlock:^(RNGestureHandlerManager *manager) {
[manager createGestureHandler:handlerName tag:[NSNumber numberWithDouble:handlerTag] config:config];
}];
RNGestureHandlerManager *manager = [RNGestureHandlerModule handlerManagerForModuleId:_moduleId];
[manager createGestureHandler:handlerName tag:[NSNumber numberWithDouble:handlerTag] config:config];

return @1;
}

- (void)attachGestureHandler:(double)handlerTag newView:(double)viewTag actionType:(double)actionType
Expand Down
11 changes: 11 additions & 0 deletions packages/react-native-gesture-handler/src/handlers/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,15 +62,26 @@ export function findNodeHandle(
}
return findNodeHandleRN(node) ?? null;
}

let scheduledOperations: (() => void)[] = [];
let flushOperationsScheduled = false;

export function scheduleFlushOperations() {
if (!flushOperationsScheduled) {
flushOperationsScheduled = true;
ghQueueMicrotask(() => {
for (const operation of scheduledOperations) {
operation();
}
scheduledOperations = [];
RNGestureHandlerModule.flushOperations();

flushOperationsScheduled = false;
});
}
}

export function scheduleOperationToBeFlushed(operation: () => void) {
scheduledOperations.push(operation);
scheduleFlushOperations();
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export interface Spec extends TurboModule {
// Record<> is not supported by codegen
// eslint-disable-next-line @typescript-eslint/ban-types
config: Object
) => void;
) => boolean;
attachGestureHandler: (
handlerTag: Double,
newView: Double,
Expand Down
54 changes: 54 additions & 0 deletions packages/react-native-gesture-handler/src/v3/NativeProxy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { scheduleOperationToBeFlushed } from '../handlers/utils';
import RNGestureHandlerModule from '../RNGestureHandlerModule';
import {
BaseGestureConfig,
GestureRelations,
SingleGestureName,
} from './types';

// Destructure functions that can be called on the UI thread to have
// a raw HostFunction reference
const { flushOperations, updateGestureHandlerConfig } = RNGestureHandlerModule;

export const NativeProxy = {
createGestureHandler: <T extends Record<string, unknown>>(
handlerName: SingleGestureName,
handlerTag: number,
config?: T
) => {
RNGestureHandlerModule.createGestureHandler(
handlerName,
handlerTag,
config || {}
);
},
setGestureHandlerConfig: <THandlerData, TConfig>(
handlerTag: number,
newConfig: BaseGestureConfig<THandlerData, TConfig>
) => {
scheduleOperationToBeFlushed(() => {
RNGestureHandlerModule.setGestureHandlerConfig(handlerTag, newConfig);
});
},
// updateGestureHandlerConfig can be called on the UI thread when using
// SharedValue binding. Therefore, it needs to be a worklet and we flush
// immediately since we're likely already on the UI thread.
updateGestureHandlerConfig: <THandlerData, TConfig>(
handlerTag: number,
newConfig: BaseGestureConfig<THandlerData, TConfig>
) => {
'worklet';
updateGestureHandlerConfig(handlerTag, newConfig);
flushOperations();
},
dropGestureHandler: (handlerTag: number) => {
scheduleOperationToBeFlushed(() => {
RNGestureHandlerModule.dropGestureHandler(handlerTag);
});
},
configureRelations: (handlerTag: number, relations: GestureRelations) => {
scheduleOperationToBeFlushed(() => {
RNGestureHandlerModule.configureRelations(handlerTag, relations);
});
},
} as const;
38 changes: 38 additions & 0 deletions packages/react-native-gesture-handler/src/v3/NativeProxy.web.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import RNGestureHandlerModule from '../RNGestureHandlerModule';
import {
BaseGestureConfig,
GestureRelations,
SingleGestureName,
} from './types';

export const NativeProxy = {
createGestureHandler: <T extends Record<string, unknown>>(
handlerName: SingleGestureName,
handlerTag: number,
config?: T
) => {
RNGestureHandlerModule.createGestureHandler(
handlerName,
handlerTag,
config || {}
);
},
setGestureHandlerConfig: <THandlerData, TConfig>(
handlerTag: number,
newConfig: BaseGestureConfig<THandlerData, TConfig>
) => {
RNGestureHandlerModule.setGestureHandlerConfig(handlerTag, newConfig);
},
updateGestureHandlerConfig: <THandlerData, TConfig>(
handlerTag: number,
newConfig: BaseGestureConfig<THandlerData, TConfig>
) => {
RNGestureHandlerModule.updateGestureHandlerConfig(handlerTag, newConfig);
},
dropGestureHandler: (handlerTag: number) => {
RNGestureHandlerModule.dropGestureHandler(handlerTag);
},
configureRelations: (handlerTag: number, relations: GestureRelations) => {
RNGestureHandlerModule.configureRelations(handlerTag, relations);
},
} as const;
12 changes: 3 additions & 9 deletions packages/react-native-gesture-handler/src/v3/detectors/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,12 @@
// For `waitFor` we need array as order of the gestures matters.
// For `simultaneousHandlers` we use Set as the order doesn't matter.

import { scheduleFlushOperations } from '../../handlers/utils';
import RNGestureHandlerModule from '../../RNGestureHandlerModule';
import { tagMessage } from '../../utils';
import {
isComposedGesture,
prepareRelations,
} from '../hooks/utils/relationUtils';
import { NativeProxy } from '../NativeProxy';
import { ComposedGestureName, Gesture } from '../types';

// The tree consists of ComposedGestures and NativeGestures. NativeGestures are always leaf nodes.
Expand All @@ -27,7 +26,7 @@ export const traverseAndConfigureRelations = (
node.gestureRelations.simultaneousHandlers.push(...simultaneousHandlers);
node.gestureRelations.waitFor.push(...waitFor);

RNGestureHandlerModule.configureRelations(node.tag, {
NativeProxy.configureRelations(node.tag, {
waitFor: node.gestureRelations.waitFor,
simultaneousHandlers: node.gestureRelations.simultaneousHandlers,
blocksHandlers: node.gestureRelations.blocksHandlers,
Expand Down Expand Up @@ -143,13 +142,8 @@ export function configureRelations<THandlerData, TConfig>(

traverseAndConfigureRelations(gesture, simultaneousHandlers);
} else {
RNGestureHandlerModule.configureRelations(
gesture.tag,
gesture.gestureRelations
);
NativeProxy.configureRelations(gesture.tag, gesture.gestureRelations);
}

scheduleFlushOperations();
}

export function ensureNativeDetectorComponent(
Expand Down
13 changes: 4 additions & 9 deletions packages/react-native-gesture-handler/src/v3/hooks/useGesture.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { useEffect, useMemo, useRef } from 'react';
import { getNextHandlerTag } from '../../handlers/getNextHandlerTag';
import RNGestureHandlerModule from '../../RNGestureHandlerModule';
import { useGestureCallbacks } from './useGestureCallbacks';
import {
prepareConfig,
Expand All @@ -11,7 +10,7 @@ import {
} from './utils';
import { tagMessage } from '../../utils';
import { BaseGestureConfig, SingleGesture, SingleGestureName } from '../types';
import { scheduleFlushOperations } from '../../handlers/utils';
import { NativeProxy } from '../NativeProxy';

export function useGesture<THandlerData, TConfig>(
type: SingleGestureName,
Expand Down Expand Up @@ -81,22 +80,18 @@ export function useGesture<THandlerData, TConfig>(
currentGestureRef.current.type !== (type as string)
) {
currentGestureRef.current = { type, tag };
RNGestureHandlerModule.createGestureHandler(type, tag, {});
// It's possible that this can cause errors about handler not being created when attempting to mount NativeDetector
scheduleFlushOperations();
NativeProxy.createGestureHandler(type, tag, {});
}

useEffect(() => {
return () => {
RNGestureHandlerModule.dropGestureHandler(tag);
scheduleFlushOperations();
NativeProxy.dropGestureHandler(tag);
};
}, [type, tag]);

useEffect(() => {
const preparedConfig = prepareConfigForNativeSide(type, config);
RNGestureHandlerModule.setGestureHandlerConfig(tag, preparedConfig);
scheduleFlushOperations();
NativeProxy.setGestureHandlerConfig(tag, preparedConfig);

bindSharedValues(config, tag);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import RNGestureHandlerModule from '../../../RNGestureHandlerModule';
import { NativeProxy } from '../../NativeProxy';
import { Reanimated } from '../../../handlers/gestures/reanimatedWrapper';
import {
BaseGestureConfig,
Expand All @@ -23,8 +23,8 @@ function hash(str: string) {

const SHARED_VALUE_OFFSET = 1.618;

// This is used to obtain HostFunction that can be executed on the UI thread
const { updateGestureHandlerConfig, flushOperations } = RNGestureHandlerModule;
// Don't transfer entire NativeProxy to the UI thread
const { updateGestureHandlerConfig } = NativeProxy;

export function bindSharedValues<THandlerData, TConfig>(
config: BaseGestureConfig<THandlerData, TConfig>,
Expand Down Expand Up @@ -52,7 +52,6 @@ export function bindSharedValues<THandlerData, TConfig>(
} else {
updateGestureHandlerConfig(handlerTag, { [configKey]: value });
}
flushOperations();
});
};

Expand Down
Loading