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

[Web] Fix `onStart` firing on `Pan` with `activateAfterLongPress` when gesture is disabled while being pressed down. #3075

Closed latekvo closed 2 months ago

latekvo commented 2 months ago

Description

Pan gesture allows for use of activateAfterLongPress modifier, which allows it to be activated after holding down the gesture down for a specified amount of time.

This modifier uses setTimeout underneath, which was not properly cleared when the gesture was disabled while being pressed down.

Closes: #3074

Test plan

Attached code

import React from 'react';
import { Button, View } from 'react-native';
import { FlashList } from '@shopify/flash-list';
import { Gesture, GestureDetector } from 'react-native-gesture-handler';

export default function HomeScreen() {
  const [enabled, setEnabled] = React.useState(true);
  const data = [0];

  const panGesture = Gesture.Pan()
    .enabled(enabled)
    .activateAfterLongPress(750)
    .onStart(() => {
      console.warn('pan triggered');
    });

  return (
    <GestureDetector gesture={panGesture}>
      <FlashList
        data={data}
        ListHeaderComponent={
          <Button
            title={enabled ? 'Disable Gestures' : 'Enable Gestures'}
            onPress={() => {
              setEnabled((prev) => !prev);
            }}
          />
        }
        renderItem={() => {
          return (
            <View
              style={{
                height: 70,
                backgroundColor: 'tomato',
              }}
            />
          );
        }}
      />
    </GestureDetector>
  );
}

Results

Collapsed results recordings ### Before https://github.com/user-attachments/assets/c09b2bc4-8b6a-4f2b-aa8c-efa78821d7f2 ### Fixed https://github.com/user-attachments/assets/5a72a363-94d4-4fdb-9060-f0f496487614

Important:

As far as I see, all the other calls to this.clearActivationTimeout() can be activated individually, and none of them are redundant.