Skip to content

Commit 8d5eec6

Browse files
authored
[Web] Don't try to remove context menu listeners when not initialized (#3814)
## Description Adds an early return inside `removeContextMenuListeners` so that it doesn't throw when `detach` and `dropHandler` are called consecutively. This is possible in v3 api, where the gesture lifecycle isn't tied to the detector component. ## Test plan Found when working on #3813, not sure how to reproduce it outside of it, but to reproduce it there use this: ``` import * as React from 'react'; import { Button, StyleSheet, Text, View } from 'react-native'; import { GestureDetector, InterceptingGestureDetector, useTap, } from 'react-native-gesture-handler'; export const COLORS = { NAVY: '#001A72', KINDA_RED: '#FFB2AD', YELLOW: '#FFF096', KINDA_GREEN: '#C4E7DB', KINDA_BLUE: '#A0D5EF', }; function TextWithTap() { const tap = useTap({ onStart: () => { 'worklet'; console.log('Tapped on text in its own component!'); }, }); return ( <GestureDetector gesture={tap}> <Text style={{ fontSize: 24, color: COLORS.KINDA_GREEN }}> This text is rendered in a separate component. </Text> </GestureDetector> ); } function NativeDetectorExample() { const [entireVisible, setEntireVisible] = React.useState(true); const [firstVisible, setFirstVisible] = React.useState(true); const [secondVisible, setSecondVisible] = React.useState(true); const [thirdVisible, setThirdVisible] = React.useState(true); const [secondKey, setSecondKey] = React.useState(0); const [firstHasCallback, setFirstHasCallback] = React.useState(true); const tapAll = useTap({ onStart: () => { 'worklet'; console.log('Tapped on text!'); }, }); const tapFirstPart = useTap({ onStart: firstHasCallback ? () => { 'worklet'; console.log('Tapped on first part!'); }: () => { 'worklet'; console.log('First part tapped, but no callback set.'); }, }); const tapSecondPart = useTap({ onStart: () => { 'worklet'; console.log('Tapped on second part!'); }, }); return ( <View style={styles.subcontainer}> <Button title={(firstVisible ? 'Hide' : 'Show') + ' entire text'} onPress={() => setEntireVisible(v => !v)} /> <Button title={(firstVisible ? 'Hide' : 'Show') + ' first part'} onPress={() => setFirstVisible(v => !v)} /> <Button title={(secondVisible ? 'Hide' : 'Show') + ' second part'} onPress={() => setSecondVisible(v => !v)} /> <Button title={(thirdVisible ? 'Hide' : 'Show') + ' third part'} onPress={() => setThirdVisible(v => !v)} /> <Button title="Re-mount second part" onPress={() => setSecondKey(k => k + 1)} /> <Button title={(firstHasCallback ? 'Disable' : 'Enable') + ' callback on first text'} onPress={() => setFirstHasCallback(v => !v)} /> {entireVisible && <InterceptingGestureDetector gesture={tapAll}> <Text style={{ fontSize: 18, textAlign: 'center' }}> Some text example running with RNGH {firstVisible && <GestureDetector gesture={tapFirstPart}> <Text style={{ fontSize: 24, color: COLORS.NAVY }}> {' '} try tapping on this part </Text> </GestureDetector>} {secondVisible && <GestureDetector gesture={tapSecondPart}> <Text key={secondKey} style={{ fontSize: 28, color: COLORS.KINDA_BLUE }}> {' '} or on this part </Text> </GestureDetector>} {thirdVisible && <> {' '} <TextWithTap /> </>} {' '} this part is not special :( </Text> </InterceptingGestureDetector>} </View> ); } export default function NativeTextExample() { return ( <View style={styles.container}> <NativeDetectorExample /> </View> ); } const styles = StyleSheet.create({ container: { flex: 1, }, subcontainer: { flex: 1, gap: 8, alignItems: 'center', justifyContent: 'center', }, header: { fontSize: 18, textAlign: 'center', paddingHorizontal: 24, }, }); ``` and press `Hide entire text`
1 parent 7b2ecaa commit 8d5eec6

File tree

1 file changed

+4
-0
lines changed

1 file changed

+4
-0
lines changed

packages/react-native-gesture-handler/src/web/tools/GestureHandlerWebDelegate.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,10 @@ export class GestureHandlerWebDelegate
139139
}
140140

141141
private removeContextMenuListeners(): void {
142+
if (!this.initialized) {
143+
return;
144+
}
145+
142146
this.ensureView(this.view);
143147

144148
if (this.shouldDisableContextMenu()) {

0 commit comments

Comments
 (0)