Repository navigation
Commit e26231e
authored
Expose the module id through a sync TurboModule method instead of a JSI global (#4525)
## Description
`GestureHandlerRootView`, `Touchable`, `NativeDetector` and
`InterceptingGestureDetector` read `globalThis._RNGH_MODULE_ID` to pass
the module id to their native views. The global is written by the
module's JSI bindings installer, which RN runs only when the
`TurboModule` is first accessed, and nothing in the library accessed it
on purpose before the root view rendered. With the default Metro config
it happened to work because evaluating the package index eagerly walks
`legacy_createNativeWrapper` → `NativeViewGestureHandler` →
`createHandler` → `RNGestureHandlerModule`, which instantiates the
module. Anything that skips that chain (the deep import from the issue,
a bundler that lowers default imports lazily, removing the v1 re-export)
leaves the global undefined, the native view gets the codegen default
`-1`, and `RNGestureHandlerRootHelper` throws "Tried to access a
non-existent registry" on mount. Debug builds never show it because
React Refresh enumerates every export of the index after it loads, which
fires the lazy getters and instantiates the module anyway.
The id is now a sync method on the module, `getModuleId`, read through a
cached `getModuleId()` helper. Asking the module for the id guarantees
the module is instantiated first, independently of bundle evaluation
order. The JSI global, `globals.ts` and the JNI field lookup are
removed. Web, Windows and the Jest mock return `-1`. The registry error
message on Android now includes the module id.
Also drops an unused `#include <string>` from the Android JNI module
header.
Fixes #4523
## Test plan
- basic-example on Android (debug) with the deep import from the issue:
crashed before, renders now.
- basic-example on Android (release) with the normal import and the
`legacy_createNativeWrapper` re-export commented out: crashed before,
renders now.
- basic-example on iOS and the Empty example on web: `Touchable`, tap
and pan detectors and `Pressable` respond
- `yarn ts-check`, `yarn lint:js`, `yarn test`.
<details>
<summary>Tested on the following code:</summary>
```tsx
// Repro for #4523 (same screen as apps/basic-example/src/Repro4523Content.tsx).
// The root view is deep-imported so nothing but the root view itself can
// instantiate the native module before it mounts. On web it is a plain View
// and the module id is -1.
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import {
GestureDetector,
Pressable,
Touchable,
usePanGesture,
useTapGesture,
} from 'react-native-gesture-handler';
import GestureHandlerRootView from 'react-native-gesture-handler/src/components/GestureHandlerRootView';
import { getModuleId } from 'react-native-gesture-handler/src/moduleId';
export default function EmptyExample() {
return (
<GestureHandlerRootView style={styles.container}>
<Repro4523Content />
</GestureHandlerRootView>
);
}
function Repro4523Content() {
const [touches, setTouches] = React.useState(0);
const [taps, setTaps] = React.useState(0);
const [presses, setPresses] = React.useState(0);
const [pan, setPan] = React.useState({ x: 0, y: 0 });
const tap = useTapGesture({
runOnJS: true,
onActivate: () => setTaps((t) => t + 1),
});
const panGesture = usePanGesture({
runOnJS: true,
onUpdate: (e) =>
setPan({ x: Math.round(e.translationX), y: Math.round(e.translationY) }),
});
return (
<View style={styles.content}>
<Text style={styles.title}>#4523 repro</Text>
<Text>module id: {getModuleId()} (increments on reload)</Text>
<Touchable
style={[styles.box, { backgroundColor: '#8e44ad' }]}
onPress={() => setTouches((t) => t + 1)}>
<Text style={styles.label}>touchable: {touches}</Text>
</Touchable>
<GestureDetector gesture={tap}>
<View style={[styles.box, { backgroundColor: '#4a90d9' }]}>
<Text style={styles.label}>tap: {taps}</Text>
</View>
</GestureDetector>
<GestureDetector gesture={panGesture}>
<View style={[styles.box, { backgroundColor: '#50b86c' }]}>
<Text style={styles.label}>
pan: {pan.x}, {pan.y}
</Text>
</View>
</GestureDetector>
<Pressable
style={({ pressed }) => [
styles.box,
{ backgroundColor: pressed ? '#b03a2e' : '#e74c3c' },
]}
onPress={() => setPresses((p) => p + 1)}>
<Text style={styles.label}>pressable: {presses}</Text>
</Pressable>
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1 },
content: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
gap: 16,
},
title: { fontSize: 20, fontWeight: 'bold' },
box: {
width: 220,
height: 80,
borderRadius: 12,
alignItems: 'center',
justifyContent: 'center',
},
label: { color: 'white', fontSize: 16 },
});
```
</details>1 parent 403cafa commit e26231e
18 files changed
Lines changed: 42 additions & 36 deletions
File tree
- packages/react-native-gesture-handler
- android/src/main
- java/com/swmansion/gesturehandler/react
- jni
- apple
- src
- components
- mocks
- specs
- v3
- components/Touchable
- detectors
- VirtualDetector
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
170 | 170 | | |
171 | 171 | | |
172 | 172 | | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
173 | 176 | | |
174 | 177 | | |
175 | 178 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
27 | 27 | | |
28 | 28 | | |
29 | 29 | | |
30 | | - | |
| 30 | + | |
| 31 | + | |
31 | 32 | | |
32 | 33 | | |
33 | 34 | | |
| |||
65 | 66 | | |
66 | 67 | | |
67 | 68 | | |
68 | | - | |
| 69 | + | |
| 70 | + | |
69 | 71 | | |
70 | 72 | | |
71 | 73 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
37 | 37 | | |
38 | 38 | | |
39 | 39 | | |
40 | | - | |
| 40 | + | |
41 | 41 | | |
42 | 42 | | |
43 | 43 | | |
| |||
73 | 73 | | |
74 | 74 | | |
75 | 75 | | |
76 | | - | |
77 | | - | |
78 | | - | |
79 | | - | |
80 | | - | |
81 | | - | |
82 | | - | |
83 | | - | |
84 | | - | |
85 | | - | |
86 | 76 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | 3 | | |
4 | | - | |
5 | 4 | | |
6 | 5 | | |
7 | 6 | | |
| |||
29 | 28 | | |
30 | 29 | | |
31 | 30 | | |
32 | | - | |
33 | 31 | | |
34 | 32 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
98 | 98 | | |
99 | 99 | | |
100 | 100 | | |
101 | | - | |
| 101 | + | |
102 | 102 | | |
103 | 103 | | |
104 | 104 | | |
| |||
209 | 209 | | |
210 | 210 | | |
211 | 211 | | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
212 | 217 | | |
213 | 218 | | |
214 | 219 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
18 | 18 | | |
19 | 19 | | |
20 | 20 | | |
21 | | - | |
22 | 21 | | |
23 | 22 | | |
24 | 23 | | |
| |||
83 | 82 | | |
84 | 83 | | |
85 | 84 | | |
86 | | - | |
87 | | - | |
88 | | - | |
89 | | - | |
90 | 85 | | |
91 | 86 | | |
92 | 87 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
17 | 17 | | |
18 | 18 | | |
19 | 19 | | |
20 | | - | |
21 | 20 | | |
22 | 21 | | |
23 | 22 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
102 | 102 | | |
103 | 103 | | |
104 | 104 | | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
105 | 108 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
47 | 47 | | |
48 | 48 | | |
49 | 49 | | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
50 | 53 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3 | 3 | | |
4 | 4 | | |
5 | 5 | | |
| 6 | + | |
6 | 7 | | |
7 | 8 | | |
8 | 9 | | |
| |||
18 | 19 | | |
19 | 20 | | |
20 | 21 | | |
21 | | - | |
| 22 | + | |
22 | 23 | | |
23 | 24 | | |
24 | 25 | | |
| |||
0 commit comments