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.13k stars 982 forks source link

Using React.StrictMode on web breaks gestures #2987

Closed chriscoomber closed 4 months ago

chriscoomber commented 4 months ago

Description

If you use React's strict mode (e.g. you wrapped your components in <React.StrictMode>, or you are using next.js and have reactStrictMode: true in your next.config.js, which is default for new apps created with create-next-app), it will break gestures on web.

The gestures are broken until the component is rendered a second time.

I have reproduced on:

Steps to reproduce

  1. Surround your app in <React.StrictMode>
  2. Run on web (with react-native-web).
  3. Try to use a gesture

Snack or a link to a repository

https://github.com/chriscoomber/RNGH-bugrepro-web-strictmode

Gesture Handler version

2.16.2

React Native version

0.74.3

Platforms

Web

JavaScript runtime

None

Workflow

None

Architecture

None

Build type

None

Device

None

Device model

No response

Acknowledgements

Yes

chriscoomber commented 4 months ago

I did some debugging, but on v2.12.1. I'm not familiar with the codebase, so I struggled a little, but I think I found out:

The Pan gesture's gesture handler is being immediately cancelled or failed because another gesture handler on the same Pan gesture tries to activate immediately after the first, which causes the first to be cancelled.

So, we want to know why there's two gesture handlers for the same Pan gesture.

Well, this line is called twice for the same instance of GestureDetector. This is somehow because of StrictMode. This means we call .initialize() twice on the same Pan gesture, and each time it adds a handler.

Past that point my debugging skills are lacking.

m-bert commented 4 months ago

Hi! @chriscoomber I've tried your reproduction and it seems to work. The thing is, you're using react-native-reanimated which still has some problems with StrictMode.

You can notice that if you drag this square and then click on re-render, it will be moved into last pointer position, which means that coordinates were assigned correctly. Also, logs from onUpdate are visible:

https://github.com/user-attachments/assets/6480ba1c-fa61-49f9-879d-9c5aa9df678f

chriscoomber commented 4 months ago

Right, my mistake.

For v2.12.1, I think there is a bug in react-native-gesture-handler. Use this branch for the reproduction: https://github.com/chriscoomber/RNGH-bugrepro-web-strictmode/tree/expo-sdk-49. onUpdate isn't being hit. When I debugged it, I found that two gesture handlers were being created. One was hitting onBegin, but then it was immediately getting cancelled/failed by the other gesture handler attempting to activate.

For v2.16.2, the bug in react-native-gesture-handler appears to be fixed already. However, the gesture still doesn't work, and this is a problem with react-native-reanimated. I'll raise there.

Since there's no bug in the latest version of react-native-gesture-handler, I'll close the issue. Thanks for your help!

chriscoomber commented 4 months ago

Issue I raised in react-native-reanimated: https://github.com/software-mansion/react-native-reanimated/issues/6264