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.12k stars 979 forks source link

Gesture.Pan() events trigger very slow #2343

Closed Willham12 closed 1 year ago

Willham12 commented 1 year ago

Description

New Pan gesture api trigger callback very slow.

Steps to reproduce


const panGesture = Gesture.Pan()
.enabled(!isDisabled)
.maxPointers(1)
.minDistance(1)
.cancelsTouchesInView(true)
.onBegin(handleGestureEvent)
.onStart(handleGestureEvent)
.onUpdate(handleGestureEvent)
.onEnd(handleGestureEvent);

### Snack or a link to a repository

https://snack.expo.dev/

### Gesture Handler version

2.8.0

### React Native version

0.70.5

### Platforms

iOS

### JavaScript runtime

Hermes

### Workflow

React Native (without Expo)

### Architecture

Paper (Old Architecture)

### Build type

Release mode

### Device

Real device

### Device model

Pixel 5, iPhone 

### Acknowledgements

Yes
github-actions[bot] commented 1 year ago

Hey! 👋

The issue doesn't seem to contain a minimal reproduction.

Could you provide a snack or a link to a GitHub repository under your username that reproduces the problem?

j-piasecki commented 1 year ago

Could you clarify what you mean by trigger callback very slow? Could you prepare a snack or a repository that reproduces the problem? Do you have Reanimated installed or not?

Willham12 commented 1 year ago

Hi, it's very hard to provide example without sharing company code. We have a infinity circular progressbar.

The old code:

<PanGestureHandler
enabled={!isDisabled}
maxPointers={1}
minDist={1}
onGestureEvent={handleGestureEvent}
onHandlerStateChange={handleGestureEvent}>
...
</PanGestureHandler>

triggers the handleGestureEvent very fast one by one

The new code:

const panGesture = Gesture.Pan()
.enabled(!isDisabled)
.maxPointers(1)
.minDistance(1)
.cancelsTouchesInView(true)
.onBegin(handleGestureEvent)
.onStart(handleGestureEvent)
.onUpdate(handleGestureEvent)
.onEnd(handleGestureEvent);

triggers the handleGestureEvent one by one with a delay. If you change the progressbar very fast the events triggering also after few seconds until the last event is finished

j-piasecki commented 1 year ago

In that case I assume you don't have Reanimated installed, so the new GH API sends the events via device events (which may be slower), instead of direct events like the old API. The main benefits of the new API come from the close integration with Reanimated which allows for synchronous communication. If you don't want to use Reanimated, then I think staying with the old API may be a good idea in your case.

Willham12 commented 1 year ago

We use reanimated for all animation so far: "react-native-reanimated": "3.0.0-rc.8",

j-piasecki commented 1 year ago

In that case, I don't have any idea off the top of my head as to what could be causing this. It will be hard to debug without more information or reproduction.

gregbrinker commented 1 year ago

I'm wondering if something in your callbacks are re-rendering the entire component. If that's the case, it will be creating new Gesture handlers with each re-render.

Can you try putting a console.log() in the onStart callback? If that prints out more than once, it means your component is being re-rendered.


EDIT: Another thing you can try is removing all your callbacks. This will prevent the gesture from causing any re-renders. Example:

const panGesture = Gesture.Pan()
.onUpdate(() => {
   console.log("Update")
})

That update should be printing out multiple times a second. If it does, that means your issue is due to your callbacks.

If that works for you, you can try adding all the other stuff one at a time until you figure out what's causing the problem.

MicahDavid commented 11 months ago

I"m migrating to v2, and having the slow down issue as well.

I've isolated the problem with changing state variables inside the callback functions. The re-rendering appears to be creating the slow down. This, however, was not an issue with version 1. Any ideas on how to get around this?

j-piasecki commented 11 months ago

If you're using Reanimated I can see two potential approaches:

  1. If you don't need the callbacks to be run on the UI thread, you can add .runOnJS(true) modifier on the configuration chain.
  2. You can try wrapping the Gesture.Pan()... invocation inside useMemo, this will prevent gestures to be recreated on every render
MicahDavid commented 10 months ago

I am using .runOnJS(true) and I tried wrapping Gesture.Pan() inside useMemo without any discernable difference. I don't see the delay issue when I use the legacy component approach.

On every touch and pan gesture the state is getting updated, so lots of re-renders, but this is not an issue with the legacy approach. Any other suggestions?

Willham12 commented 8 months ago

Still the same issue with v2.15.0. Nothing wrong on my site because it's working very well with the old api.

Vaib215 commented 6 months ago

This issue is still there and it is causing the view to re-render multiple times

Vaib215 commented 6 months ago

Please reopen this issue