software-mansion / react-native-gesture-handler

Declarative API exposing platform native touch and gesture system to React Native.
https://docs.swmansion.com/react-native-gesture-handler/
MIT License
6.14k stars 982 forks source link

Fix GestureDetector not working correctly with suspense and recycling #2925

Closed j-piasecki closed 6 months ago

j-piasecki commented 6 months ago

Description

Fixes https://github.com/software-mansion/react-native-gesture-handler/issues/2920

When the subtree containing GestureDetector was suspended, all the native views were unmounted without the Detector component being aware. As a consequence, the view with the attached native recognizer was put in the recycling pool and then reused in other places in the UI (which is bad). Then, when the tree was unsuspended, the gesture didn't work correctly - again, Detector wasn't aware of any change, and a different native view was put as its child so the native recognizer wasn't attached to it.

This PR changes the effect responsible for the initial setup and cleanup to be a layout effect, which gets triggered when the tree is suspended. This means that when tree suspends, native recognizers will be dropped and recreated when the tree unsuspends.

Note that this will only fix the issue on RN 0.74, since useLayoutEffect is broken on versions below that.

Test plan

Tested on the example app and the following code ```jsx import {useState} from 'react'; import {Freeze} from 'react-freeze'; import {View, Button, SafeAreaView} from 'react-native'; import { Gesture, GestureDetector, GestureHandlerRootView, } from 'react-native-gesture-handler'; export default function FirstScreen() { const [frozen, setFrozen] = useState(false); const tap = Gesture.Tap().onStart(() => { console.log('Tap'); }); return (