|
| 1 | +--- |
| 2 | +id: wrapped-components |
| 3 | +title: Wrapped Components |
| 4 | +sidebar_label: Wrapped Components |
| 5 | +--- |
| 6 | + |
| 7 | +Some components come with a [`Native`](/docs/gestures/use-native-gesture) gesture pre-applied. This allows them to participate in the gesture recognition process. Have a look at the example below. |
| 8 | + |
| 9 | +```tsx |
| 10 | +import { useState } from 'react'; |
| 11 | +import { Switch } from 'react-native'; |
| 12 | +import { |
| 13 | + GestureDetector, |
| 14 | + GestureHandlerRootView, |
| 15 | + useTapGesture, |
| 16 | + Switch as RNGHSwitch, |
| 17 | +} from 'react-native-gesture-handler'; |
| 18 | + |
| 19 | +export default function App() { |
| 20 | + const [isEnabled, setIsEnabled] = useState(false); |
| 21 | + |
| 22 | + const tap1 = useTapGesture({ |
| 23 | + onDeactivate: () => { |
| 24 | + console.log('Tapped!'); |
| 25 | + }, |
| 26 | + }); |
| 27 | + |
| 28 | + const tap2 = useTapGesture({ |
| 29 | + onDeactivate: () => { |
| 30 | + console.log('Tapped!'); |
| 31 | + }, |
| 32 | + }); |
| 33 | + |
| 34 | + return ( |
| 35 | + <GestureHandlerRootView style={{ flex: 1, paddingTop: 100 }}> |
| 36 | + <GestureDetector gesture={tap1}> |
| 37 | + <Switch value={isEnabled} onValueChange={setIsEnabled} /> |
| 38 | + </GestureDetector> |
| 39 | + <GestureDetector gesture={tap2}> |
| 40 | + <RNGHSwitch value={isEnabled} onValueChange={setIsEnabled} /> |
| 41 | + </GestureDetector> |
| 42 | + </GestureHandlerRootView> |
| 43 | + ); |
| 44 | +} |
| 45 | +``` |
| 46 | + |
| 47 | +On Android, in this scenario, the `Switch` from React Native cannot be toggled on because the `tap1` gesture intercepts it. However, using `RNGHSwitch` makes it capable of participating in the gesture recognition process. This setup allows the switch to be toggled on while still enabling `tap2` to recognize taps on it. |
| 48 | + |
| 49 | +## List of wrapped components |
| 50 | + |
| 51 | +Components listed below come with a pre-applied `Native` gesture. |
| 52 | + |
| 53 | +- `FlatList` |
| 54 | +- `ScrollView` |
| 55 | +- `RefreshControl` |
| 56 | +- `TextInput` |
| 57 | +- `Switch` |
| 58 | + |
| 59 | +## onGestureUpdate_CAN_CAUSE_INFINITE_RERENDER |
| 60 | + |
| 61 | +:::danger |
| 62 | +This callback may lead to infinite re-renders if not used carefully. |
| 63 | + |
| 64 | +```tsx |
| 65 | +export default function App() { |
| 66 | + const [gesture, setGesture] = useState<NativeGesture | null>(null); |
| 67 | + |
| 68 | + const updateGesture = (g: NativeGesture) => { |
| 69 | + // ❌ Wrong usage: calling setState here triggers a re-render, |
| 70 | + // which re-creates the ScrollView's Native gesture, which fires |
| 71 | + // this callback again → infinite re-render loop. |
| 72 | + setGesture(g); |
| 73 | + }; |
| 74 | + |
| 75 | + return ( |
| 76 | + <GestureHandlerRootView style={{ flex: 1 }}> |
| 77 | + <ScrollView onGestureUpdate_CAN_CAUSE_INFINITE_RERENDER={updateGesture} /> |
| 78 | + </GestureHandlerRootView> |
| 79 | + ); |
| 80 | +} |
| 81 | +``` |
| 82 | +::: |
| 83 | + |
| 84 | +Those components also receive an additional prop named `onGestureUpdate_CAN_CAUSE_INFINITE_RERENDER`. |
| 85 | + |
| 86 | +```ts |
| 87 | +onGestureUpdate_CAN_CAUSE_INFINITE_RERENDER?: (gesture: NativeGesture) => void; |
| 88 | +``` |
| 89 | + |
| 90 | +This callback is invoked when the wrapped component's underlying `Native` gesture instance or configuration changes, providing access to the underlying gesture. This can be helpful when setting up [relations](/docs/fundamentals/gesture-composition) with other gestures. You can check example usage in our [`ScrollView`](https://github.com/software-mansion/react-native-gesture-handler/blob/main/packages/react-native-gesture-handler/src/v3/components/GestureComponents.tsx#L78) component. |
0 commit comments