gesture-handler-3-migration

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Migrate to Gesture Handler 3

迁移至Gesture Handler 3

This skill scans React Native components that use the Gesture Handler builder-based API and updates them to use the new hook-based API. It also updates related types and components to adapt to the new version.
本Skill会扫描使用Gesture Handler基于构建器API的React Native组件,并将其更新为使用新的基于Hook的API。同时还会更新相关类型与组件以适配新版本。

When to Use

使用场景

  • Updating the usage of components imported from
    react-native-gesture-handler
  • Upgrading to Gesture Handler 3
  • Migrating to the new hook-based gesture API
  • 更新从
    react-native-gesture-handler
    导入的组件用法
  • 升级至Gesture Handler 3版本
  • 迁移至新的基于Hook的手势API

Instructions

操作步骤

Use the instructions below to correctly replace all legacy APIs with the modern ones.
  1. Identify all imports from 'react-native-gesture-handler'
  2. For each
    Gesture.X()
    call, replace with corresponding
    useXGesture()
    hook
  3. Replace
    Gesture
    import with imports for the used hooks
  4. Convert builder method chains to configuration objects
  5. Update callback names (onStart → onActivate, etc.)
  6. Replace composed gestures with relation hooks. Keep rules of hooks in mind
  7. Update GestureDetector usage if SVG is involved to Intercepting/Virtual GestureDetector
  8. Update usage of compoenent imported from 'react-native-gesture-handler' according to "Legacy components" section
请按照以下说明将所有旧版API正确替换为新版API。
  1. 识别所有从'react-native-gesture-handler'导入的内容
  2. 将每个
    Gesture.X()
    调用替换为对应的
    useXGesture()
    Hook
  3. Gesture
    导入替换为所使用Hook的导入
  4. 将构建器方法链转换为配置对象
  5. 更新回调名称(如onStart → onActivate等)
  6. 使用关联Hook替换组合手势,注意Hook的使用规则
  7. 若涉及SVG,将GestureDetector的用法更新为Intercepting/Virtual GestureDetector
  8. 根据「旧版组件」章节更新从'react-native-gesture-handler'导入的组件用法

Migrating gestures

迁移手势

All hook gestures have their counterparts in the builder API:
Gesture.X()
becomes
useXGesture(config)
. The methods are now config object fields with the same name as the relevant builder methods, unless specified otherwise.
The exception to thait is
Gesture.ForceTouch
which DOES NOT have a counterpart in the hook API.
所有Hook手势在构建器API中都有对应的版本:
Gesture.X()
变为
useXGesture(config)
。方法现在是配置对象的字段,名称与相关构建器方法相同,除非另有说明。
例外情况是
Gesture.ForceTouch
,它在Hook API中没有对应版本。

Callback changes

回调变更

In Gesture Handler 3 some of the callbacks were renamed, namely:
  • onStart
    ->
    onActivate
  • onEnd
    ->
    onDeactivate
  • onTouchesCancelled
    ->
    onTouchesCancel
In the hooks API
onChange
is no longer available. Instead the
*change*
properties were moved to the event available inside
onUpdate
.
All callbacks of a gesture are now using the same type:
  • usePanGesture()
    ->
    PanGestureEvent
  • useTapGesture()
    ->
    TapGestureEvent
  • useLongPressGesture()
    ->
    LongPressGestureEvent
  • useRotationGesture()
    ->
    RotationGestureEvent
  • usePinchGesture()
    ->
    PinchGestureEvent
  • useFlingGesture()
    ->
    FlingGestureEvent
  • useHoverGesture()
    ->
    HoverGestureEvent
  • useNativeGesture()
    ->
    RotationGestureEvent
  • useManualGesture()
    ->
    ManualGestureEvent
The exception to this is touch events:
  • onTouchesDown
  • onTouchesUp
  • onTouchesMove
  • onTouchesCancel
Where each callback receives
GestureTouchEvent
regardless of the hook used.
在Gesture Handler 3中,部分回调名称被重命名,具体如下:
  • onStart
    ->
    onActivate
  • onEnd
    ->
    onDeactivate
  • onTouchesCancelled
    ->
    onTouchesCancel
在Hook API中,
onChange
不再可用。取而代之的是,
*change*
属性被移至
onUpdate
内部的事件中。
手势的所有回调现在使用相同的类型:
  • usePanGesture()
    ->
    PanGestureEvent
  • useTapGesture()
    ->
    TapGestureEvent
  • useLongPressGesture()
    ->
    LongPressGestureEvent
  • useRotationGesture()
    ->
    RotationGestureEvent
  • usePinchGesture()
    ->
    PinchGestureEvent
  • useFlingGesture()
    ->
    FlingGestureEvent
  • useHoverGesture()
    ->
    HoverGestureEvent
  • useNativeGesture()
    ->
    RotationGestureEvent
  • useManualGesture()
    ->
    ManualGestureEvent
触摸事件是例外情况:
  • onTouchesDown
  • onTouchesUp
  • onTouchesMove
  • onTouchesCancel
无论使用哪个Hook,这些回调都会接收
GestureTouchEvent
类型。

StateManager

StateManager

In Gesture Handler 3,
stateManager
is no longer passed to
TouchEvent
callbacks. Instead, you should use the global
GestureStateManager
.
GestureStateManager
provides methods for imperative state management:
  • .begin(handlerTag: number)
  • .activate(handlerTag: number)
  • .deactivate(handlerTag: number) (.end() in the old API)
  • .fail(handlerTag: number)
handlerTag
can be obtained in two ways:
  1. From the gesture object returned by the hook (
    gesture.handlerTag
    )
  2. From the event inside callback (
    event.handlerTag
    )
Callback definitions CANNOT reference the gesture that's being defined. In this scenario use events to get access to the handler tag.
在Gesture Handler 3中,
stateManager
不再传递给
TouchEvent
回调。取而代之的是,你应该使用全局的
GestureStateManager
GestureStateManager
提供了命令式状态管理的方法:
  • .begin(handlerTag: number)
  • .activate(handlerTag: number)
  • .deactivate(handlerTag: number)(旧版API中的.end())
  • .fail(handlerTag: number)
handlerTag
可以通过两种方式获取:
  1. 从Hook返回的手势对象中获取(
    gesture.handlerTag
  2. 从回调内部的事件中获取(
    event.handlerTag
回调定义不能引用正在定义的手势。在这种情况下,请使用事件来访问handler tag。

Migrating relations

迁移关联关系

Composed gestures

组合手势

Gesture.Simultaneous(gesture1, gesture2);
becomes
useSimultaneousGestures(pan1, pan2);
All relations from the old API and their counterparts in the new one:
  • Gesture.Race()
    ->
    useCompetingGestures()
  • Gesture.Simultaneous()
    ->
    useSimultaneousGestures()
  • Gesture.Exclusive()
    ->
    useExclusiveGestures()
Gesture.Simultaneous(gesture1, gesture2);
变为
useSimultaneousGestures(pan1, pan2);
旧版API中的所有关联关系及其在新版中的对应项:
  • Gesture.Race()
    ->
    useCompetingGestures()
  • Gesture.Simultaneous()
    ->
    useSimultaneousGestures()
  • Gesture.Exclusive()
    ->
    useExclusiveGestures()

Cross components relations properties

跨组件关联属性

Properties used to define cross-components interactions were renamed:
  • .simultaneousWithExternalGesture
    ->
    simultaneousWith:
  • .requireExternalGestureToFail
    ->
    requireToFail:
  • .blocksExternalGesture
    ->
    block:
用于定义跨组件交互的属性被重命名:
  • .simultaneousWithExternalGesture
    ->
    simultaneousWith:
  • .requireExternalGestureToFail
    ->
    requireToFail:
  • .blocksExternalGesture
    ->
    block:

GestureDetector

GestureDetector

The
GestureDetector
is a key component of
react-native-gesture-handler
. It supports gestures created either using the hooks API or the builder pattern (but those cannot be mixed, it's either or).
Don't use the same instance of a gesture across multiple Gesture Detectors as it will lead to an undefined behavior.
GestureDetector
react-native-gesture-handler
的核心组件。它支持使用Hook API或构建器模式创建的手势(但不能混合使用,只能二选一)。
不要在多个Gesture Detector中使用同一个手势实例,这会导致未定义行为。

Integration with Reanimated

与Reanimated集成

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.
This will not be workletized because the callback is defined outside of the gesture object:
jsx
const callback = () => {
  console.log(_WORKLET);
};

const gesture = useTapGesture({
  onBegin: callback,
});
The callback wrapped by any other higher order function will not be workletized:
jsx
const gesture = useTapGesture({
  onBegin: useCallback(() => {
    console.log(_WORKLET);
  }, []),
});
In the above cases, you should add a
"worklet";
directive as the first line of the callback.
Worklets的Babel插件会自动将配置链中传递给手势的回调标记为worklet。这意味着你不需要在函数开头添加
'worklet';
指令。
以下情况不会被标记为worklet,因为回调是在手势对象外部定义的:
jsx
const callback = () => {
  console.log(_WORKLET);
};

const gesture = useTapGesture({
  onBegin: callback,
});
被任何高阶函数包裹的回调也不会被标记为worklet:
jsx
const gesture = useTapGesture({
  onBegin: useCallback(() => {
    console.log(_WORKLET);
  }, []),
});
在上述情况下,你应该在回调的第一行添加
"worklet";
指令。

Disabling Reanimated

禁用Reanimated

Gestures created with the hook API have
Reanimated
integration enabled by default (if it's installed), meaning all callbacks are executed on the UI thread.
使用Hook API创建的手势默认启用Reanimated集成(如果已安装),这意味着所有回调都在UI线程上执行。

runOnJS

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 is
false
.
runOnJS
属性允许你动态控制回调是在JS线程还是UI线程上执行。设置为
true
时,回调将在JS线程上运行;设置为
false
时,将在UI线程上执行。默认值为
false

Migrating components relying on view hierarchy

迁移依赖视图层级的组件

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
.
InterceptingGestureDetector
functions similarly to the
GestureDetector
, but it can also act as a proxy for
VirtualGestureDetector
within its component subtree. Because it can be used solely to establish the context for virtual detectors, the
gesture
property is optional.
VirtualGestureDetector
is similar to the
GestureDetector
from RNGH2. Because it is not a host component, it does not interfere with the host view hierarchy. This allows you to attach gestures without disrupting functionality that depends on it.
Warning:
VirtualGestureDetector
has to be a descendant of
InterceptingGestureDetector
.
某些组件(如
SVG
)依赖视图层级才能正常工作。在Gesture Handler 3中,
GestureDetector
会破坏这些层级关系。为解决此问题,引入了两个新的检测器:
InterceptingGestureDetector
VirtualGestureDetector
InterceptingGestureDetector
的功能与
GestureDetector
类似,但它还可以作为其子组件树中
VirtualGestureDetector
的代理。由于它可以仅用于为虚拟检测器建立上下文,因此
gesture
属性是可选的。
VirtualGestureDetector
与RNGH2中的
GestureDetector
类似。由于它不是宿主组件,因此不会干扰宿主视图层级。这允许你在不破坏依赖视图层级的功能的情况下附加手势。
警告:
VirtualGestureDetector
必须是
InterceptingGestureDetector
的后代组件。

Migrating SVG

迁移SVG

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
.
在Gesture Handler 2中,可以直接在
SVG
上使用
GestureDetector
。在Gesture Handler 3中,与
SVG
交互的正确方式是使用
InterceptingGestureDetector
VirtualGestureDetector

Legacy components

旧版组件

When the code using the component relies on the APIs that are no longer available on the components in Gesture Handler 3 (like
waitFor
,
simultaneousWith
,
blocksHandler
,
onHandlerStateChange
,
onGestureEvent
props), it cannot be easily migrated in isolation. In this case update the imports to the Legacy version of the component, and inform the user that the dependencies need to be migrated first.
If the migration is possible, use the ask questions tool to clarify the user intent unless clearly stated beforehand: should the components be using the new implementation (no
Legacy
prefix when imported), or should they revert to the old implementation (
Legacy
prefix when imported)?
Don't suggest replacing buttons from Gesture Handler with components from React Native and vice versa.
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 legacy JS implementations of button components are still accessible but have been renamed with the prefix
Legacy
, e.g.,
RectButton
is now available as
LegacyRectButton
. Those still use the new native component under the hood.
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 legacy components are also available and are prefixed with
Legacy
, e.g.,
ScrollView
is now available as
LegacyScrollView
.
当使用组件的代码依赖Gesture Handler 3组件中不再可用的API(如
waitFor
simultaneousWith
blocksHandler
onHandlerStateChange
onGestureEvent
属性)时,无法单独轻松迁移。在这种情况下,请将导入更新为组件的旧版(Legacy)版本,并告知用户需要先迁移依赖项。
如果可以迁移,请使用提问工具明确用户的意图(除非之前已明确说明):组件应使用新实现(导入时不带
Legacy
前缀),还是应恢复为旧实现(导入时带
Legacy
前缀)?
不要建议将Gesture Handler的按钮替换为React Native的组件,反之亦然。
按钮的实现已更新,解决了大多数与按钮相关的问题。它们也已内部重写为使用新的Hook API。按钮组件的旧版JS实现仍然可用,但已重命名为带
Legacy
前缀,例如
RectButton
现在可作为
LegacyRectButton
使用。这些组件仍然在底层使用新的原生组件。
其他组件也已内部使用新的Hook API重写,但仍以原名称导出,因此你无需进行任何更改。不过,如果你因任何原因需要使用之前的实现,旧版组件也可用,且带有
Legacy
前缀,例如
ScrollView
现在可作为
LegacyScrollView
使用。

Replaced types

已替换的类型

Most of the types used in the builder API, like
TapGesture
, are still present in Gesture Handler 3. However, they are now used in new hook API. Types for builder API now have
Legacy
prefix, e.g.
TapGesture
becomes
LegacyTapGesture
.
构建器API中使用的大多数类型(如
TapGesture
)在Gesture Handler 3中仍然存在。但它们现在用于新的Hook API。构建器API的类型现在带有
Legacy
前缀,例如
TapGesture
变为
LegacyTapGesture