| id | upgrading-to-3 |
|---|---|
| title | Upgrading to the new API introduced in Gesture Handler 3 |
import CodeComparison from '@site/src/components/CodeComparison';
The most important change brought by the Gesture Handler 3 is the new hook API. Migration is pretty straightforward. Instead of calling builder methods, everything is passed as a configuration object.
<CodeComparison
label1={"RNGH 2"}
label2={"RNGH 3"}
code1={
const gesture = Gesture.Pan() .onBegin(() => { console.log('Pan!'); }) .minDistance(25); }
code2={
const gesture = usePanGesture({ onBegin: () => { console.log('Pan!'); }, minDistance: 25, }); }
/>
ForceTouch gesture is not available in hook API.
Full changes
| RNGH2 | RNGH3 |
|---|---|
Gesture.Pan() |
usePanGesture() |
Gesture.Tap() |
useTapGesture() |
Gesture.LongPress() |
useLongPressGesture() |
Gesture.Rotation() |
useRotationGesture() |
Gesture.Pinch() |
usePinchGesture() |
Gesture.Fling() |
useFlingGesture() |
Gesture.Hover() |
useHoverGesture() |
Gesture.Native() |
useNativeGesture() |
Gesture.Manual() |
useManualGesture() |
Gesture.ForceTouch() |
Not available in hook API |
In Gesture Handler 3 some of the callbacks were renamed, namely:
| RNGH2 | RNGH3 |
|---|---|
onStart |
onActivate |
onEnd |
onDeactivate |
onTouchesCancelled |
onTouchesCancel |
Here is comparison of the two APIs:
<CodeComparison
label1={"RNGH 2"}
label2={"RNGH 3"}
code1={
const gesture = Gesture.Pan() .onStart(() => { console.log('Pan started!'); }) .onEnd(() => { console.log('Pan ended!'); }) .onTouchesCancelled(() => { console.log('Pan touches cancelled!'); }); }
code2={
const gesture = usePanGesture({ onActivate: () => { console.log('Pan activated!'); }, onDeactivate: () => { console.log('Pan deactivated!'); }, onTouchesCancel: () => { console.log('Pan touches cancelled!'); }, }); }
/>
onChange callback has been removed, and its functionality has been integrated into onUpdate. You can now access change* properties in onUpdate callback.
<CodeComparison
label1={"RNGH 2"}
label2={"RNGH 3"}
code1={
const pan = Gesture.Pan().onChange((e) => { console.log(e.changeX); }); }
code2={
const pan = usePanGesture({ onUpdate: (e) => { console.log(e.changeX); }, }); }
/>
The state and oldState properties are no longer available in event objects. Tracking state changes can now only be accomplished using the appropriate callbacks.
The types of events have been unified for all callbacks. Each event falls into one of two categories: GestureEvent for gesture callbacks, or GestureTouchEvent for TouchEvent callbacks.
In Gesture Handler 3, stateManager is no longer passed to TouchEvent callbacks. Instead, you should use the global GestureStateManager.
<CodeComparison
label1={"RNGH 2"}
label2={"RNGH 3"}
code1={
const manual = Gesture.Manual().onTouchesDown((e, stateManager ) => { stateManager.activate(); }); }
code2={
const manual = useManualGesture({ onTouchesDown: (e) => { GestureStateManager.activate(e.handlerTag); }, }); }
/>
Previously, composed gestures were created using Gesture object. In Gesture Handler 3, relations are set up using relation hooks.
<CodeComparison label1={"RNGH 2"} label2={"RNGH 3"} code1={ `const pan1 = Gesture.Pan(); const pan2 = Gesture.Pan();
const gesture = Gesture.Simultaneous(pan1, pan2);
} code2={ const pan1 = usePanGesture({});
const pan2 = usePanGesture({});
const gesture = useSimultaneousGestures(pan1, pan2); `} />
Full changes are as follows:
| RNGH2 | RNGH3 |
|---|---|
Gesture.Race() |
useCompetingGestures() |
Gesture.Simultaneous() |
useSimultaneousGestures() |
Gesture.Exclusive() |
useExclusiveGestures() |
Properties used to define cross-components interactions were renamed.
<CodeComparison
label1={"RNGH 2"}
label2={"RNGH 3"}
code1={
const pan1 = Gesture.Pan(); const pan2 = Gesture.Pan().requireExternalGestureToFail(pan1); }
code2={
const pan1 = usePanGesture({}); const pan2 = usePanGesture({ requireToFail: pan1, }); }
/>
Full changes are as follows:
| RNGH2 | RNGH3 |
|---|---|
gesture.simultaneousWithExternalGesture |
gesture.simultaneousWith |
gesture.requireExternalGestureToFail |
gesture.requireToFail |
gesture.blocksExternalGesture |
gesture.block |
Certain components, such as SVG, depend on the view hierarchy to function correctly. In Gesture Handler 3, GestureDetector disrupts these hierarchies. To resolve this issue, two new detectors have been introduced: InterceptingGestureDetector and VirtualGestureDetector.
:::danger Detectors order
VirtualGestureDetector has to be a descendant of InterceptingGestureDetector.
:::
In Gesture Handler 2 it was possible to use GestureDetector directly on SVG. In Gesture Handler 3, the correct way to interact with SVG is to use InterceptingGestureDetector and VirtualGestureDetector.
<CodeComparison
label1={"RNGH 2"}
label2={"RNGH 3"}
code1={
<GestureDetector gesture={containerTap}> <Svg> <GestureDetector gesture={circleTap}> <Circle /> </GestureDetector> </Svg> </GestureDetector>}
code2={
<InterceptingGestureDetector gesture={containerTap}> <Svg> <VirtualGestureDetector gesture={circleTap}> <Circle /> </VirtualGestureDetector> </Svg> </InterceptingGestureDetector>}
/>
The implementation of buttons has been updated, resolving most button-related issues. They have also been internally rewritten to utilize the new hook API. The original button components are still accessible but have been renamed with the prefix Legacy, e.g., RectButton is now available as LegacyRectButton.
Although the legacy JS implementation of the buttons is still available, they also use the new host component internally. Because of that, PureNativeButton is no longer available in Gesture Handler 3.
Legacy buttons
| RNGH2 | RNGH3 |
|---|---|
RawButton |
LegacyRawButton |
BaseButton |
LegacyBaseButton |
RectButton |
LegacyRectButton |
BorderlessButton |
LegacyBorderlessButton |
PureNativeButton |
Not available in Gesture Handler 3 |
Other components have also been internally rewritten using the new hook API but are exported under their original names, so no changes are necessary on your part. However, if you need to use the previous implementation for any reason, the old components are also available and are prefixed with Legacy, e.g., ScrollView is now available as LegacyScrollView.
Legacy components
| RNGH2 | RNGH3 |
|---|---|
ScrollView |
LegacyScrollView |
FlatList |
LegacyFlatList |
RefreshControl |
LegacyRefreshControl |
Switch |
LegacySwitch |
TextInput |
LegacyTextInput |
DrawerLayoutAndroid |
LegacyDrawerLayoutAndroid |
Most of the types, like TapGesture, are still present in Gesture Handler 3. However, they are now used in new hook API. Types for old API now have Legacy prefix, e.g. TapGesture becomes LegacyTapGesture.
Legacy types
| RNGH2 | RNGH3 |
|---|---|
PanGesture |
LegacyPanGesture |
TapGesture |
LegacyTapGesture |
LongPressGesture |
LegacyLongPressGesture |
RotationGesture |
LegacyRotationGesture |
PinchGesture |
LegacyPinchGesture |
FlingGesture |
LegacyFlingGesture |
HoverGesture |
LegacyHoverGesture |
NativeGesture |
LegacyNativeGesture |
ManualGesture |
LegacyManualGesture |
ForceTouchGesture |
LegacyForceTouchGesture |
ComposedGesture |
LegacyComposedGesture |
RaceGesture |
LegacyRaceGesture |
SimultaneousGesture |
LegacySimultaneousGesture |
ExclusiveGesture |
LegacyExclusiveGesture |
RawButtonProps |
LegacyRawButtonProps |
BaseButtonProps |
LegacyBaseButtonProps |
RectButtonProps |
LegacyRectButtonProps |
BorderlessButtonProps |
LegacyBorderlessButtonProps |