Skip to main content
Version: 3.x

Integration with Reanimated

GestureDetector will decide whether to use Reanimated to process provided gestures based on their configuration. If any of the callbacks is a worklet and Reanimated is not explicitly turned off, tools provided by the Reanimated will be utilized, bringing the ability to handle gestures synchronously on the main thread.

Automatic workletization of gesture callbacks

Worklets' Babel plugin is setup in a way that automatically marks callbacks passed to gestures in the configuration chain as worklets. This means that you don't need to add a 'worklet'; directive at the beginning of the functions. Here is an example that will be automatically workletized:

const gesture = useTapGesture({
onBegin: () => {
console.log(_WORKLET);
},
});

And here is one that won't:

const callback = () => {
console.log(_WORKLET);
};

const gesture = useTapGesture({
onBegin: callback,
});

It also won't work when wrapped with hooks like useCallback or useMemo, e.g:

const callback = useCallback(() => {
console.log(_WORKLET);
}, []);

const gesture = useTapGesture({
onBegin: callback,
});

In the above cases, you should add a "worklet"; directive at the beginning of the callbacks, like so:

const callback = () => {
'worklet';
console.log(_WORKLET);
};

const gesture = useTapGesture({
onBegin: callback,
});
const callback = useCallback(() => {
'worklet;';
console.log(_WORKLET);
}, []);

const gesture = useTapGesture({
onBegin: callback,
});

Using SharedValue in gesture config

RNGH3 allows to pass SharedValue to gestures' configurations. This allows to react to configuration changes without unnecessary rerenders.

export default function App() {
const taps = useSharedValue(2);

const gesture = useTapGesture({
numberOfTaps: taps,
onDeactivate: () => {
taps.value += 1;
},

Disabling Reanimated

Gestures created with the hook API have Reanimated integration enabled by default, meaning all callbacks are executed on the UI thread. There are two methods available to disable this behavior for a specific gesture.

disableReanimated

When disableReanimated is set to true in the gesture configuration, Reanimated integration will be completely turned off for that gesture throughout its entire lifecycle. This setting eliminates all interaction points with Reanimated, thereby reducing any potential overhead. Default value for this property is false.

This property cannot be changed dynamically during the gesture's lifecycle.

const gesture = usePanGesture({
disableReanimated: true,

onUpdate: () => {
console.log('Panning');
},
});

runOnJS

The runOnJS property allows you to dynamically control whether callbacks are executed on the JS thread or the UI thread. When set to true, callbacks will run on the JS thread. Setting it to false will execute them on the UI thread. Default value for this property is false.

This property can be changed dynamically throughout the gesture's lifecycle.


export default function App() {
const shouldRunOnJS = useSharedValue(false);

const panGesture = usePanGesture({
onUpdate: () => {
console.log(
globalThis.__RUNTIME_KIND === 2
? 'Running on UI thread'
: 'Running on JS thread'
);
},
onDeactivate: () => {
shouldRunOnJS.value = !shouldRunOnJS.value;
},
runOnJS: shouldRunOnJS,
});

return (
<GestureHandlerRootView style={styles.container}>
<View style={styles.outerBox}>
<GestureDetector gesture={panGesture}>
<Animated.View style={styles.innerBox} />
</GestureDetector>
</View>
</GestureHandlerRootView>
);