Skip to content

Commit

Permalink
Remove event listeners on handler drop (#2815)
Browse files Browse the repository at this point in the history
## Description

Right now when handlers are dropped, event listeners are not removed from view. I think this might cause problems with SSR. With this PR, listeners are properly removed from underlying view.

### Before

https://github.com/software-mansion/react-native-gesture-handler/assets/63123542/e676a513-d505-41db-b302-96538d585c70

### After

https://github.com/software-mansion/react-native-gesture-handler/assets/63123542/5aa8a319-17c4-4ca5-9f44-bbc60b6d0fe3

## Test plan

1. Run the following code:

<details>
<summary>Test code</summary>

```jsx
import React, { useState } from 'react';
import { StyleSheet, View } from 'react-native';
import { Gesture, GestureDetector } from 'react-native-gesture-handler';

export default function EmptyExample() {
  const fling = Gesture.Fling();
  const tap = Gesture.Tap();

  const [g, setG] = useState<any>(fling);

  setTimeout(() => {
    setG(tap);
    console.log('Switching gesture to tap');
  }, 1500);

  return (
    <View style={styles.container}>
      <GestureDetector gesture={g}>
        <View style={[styles.circle, { backgroundColor: 'crimson' }]} />
      </GestureDetector>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },

  circle: {
    width: 150,
    height: 150,
    borderRadius: 75,
  },
});

```

</details>

2. Select red circle with inspector and navigate to `Event Listeners`
3. Check that only one listener is present after `Gesture` was changed
  • Loading branch information
m-bert authored Mar 21, 2024
1 parent 84ba3b2 commit baffb68
Show file tree
Hide file tree
Showing 7 changed files with 335 additions and 299 deletions.
3 changes: 2 additions & 1 deletion src/web/handlers/GestureHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ export default abstract class GestureHandler implements IGestureHandler {
manager.setOnPointerOutOfBounds(this.onPointerOutOfBounds.bind(this));
manager.setOnPointerMoveOver(this.onPointerMoveOver.bind(this));
manager.setOnPointerMoveOut(this.onPointerMoveOut.bind(this));
manager.setListeners();

manager.registerListeners();
}

//
Expand Down
5 changes: 5 additions & 0 deletions src/web/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,11 @@ interface NativeEvent extends Record<string, NativeEventArgs> {
pointerType: PointerType;
}

export interface Point {
x: number;
y: number;
}

export interface PointerData {
id: number;
x: number;
Expand Down
30 changes: 16 additions & 14 deletions src/web/tools/EventManager.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
/* eslint-disable @typescript-eslint/no-empty-function */
import { AdaptedEvent, EventTypes, TouchEventType } from '../interfaces';

type PointerEventCallback = (event: AdaptedEvent) => void;

export default abstract class EventManager<T> {
protected readonly view: T;
protected pointersInBounds: number[] = [];
Expand All @@ -11,7 +13,9 @@ export default abstract class EventManager<T> {
this.activePointersCounter = 0;
}

public abstract setListeners(): void;
public abstract registerListeners(): void;
public abstract unregisterListeners(): void;

protected abstract mapEvent(
event: Event,
eventType: EventTypes,
Expand All @@ -36,39 +40,37 @@ export default abstract class EventManager<T> {
protected onPointerMoveOver(_event: AdaptedEvent): void {}
protected onPointerMoveOut(_event: AdaptedEvent): void {}

public setOnPointerDown(callback: (event: AdaptedEvent) => void): void {
public setOnPointerDown(callback: PointerEventCallback): void {
this.onPointerDown = callback;
}
public setOnPointerAdd(callback: (event: AdaptedEvent) => void): void {
public setOnPointerAdd(callback: PointerEventCallback): void {
this.onPointerAdd = callback;
}
public setOnPointerUp(callback: (event: AdaptedEvent) => void): void {
public setOnPointerUp(callback: PointerEventCallback): void {
this.onPointerUp = callback;
}
public setOnPointerRemove(callback: (event: AdaptedEvent) => void): void {
public setOnPointerRemove(callback: PointerEventCallback): void {
this.onPointerRemove = callback;
}
public setOnPointerMove(callback: (event: AdaptedEvent) => void): void {
public setOnPointerMove(callback: PointerEventCallback): void {
this.onPointerMove = callback;
}
public setOnPointerLeave(callback: (event: AdaptedEvent) => void): void {
public setOnPointerLeave(callback: PointerEventCallback): void {
this.onPointerLeave = callback;
}
public setOnPointerEnter(callback: (event: AdaptedEvent) => void): void {
public setOnPointerEnter(callback: PointerEventCallback): void {
this.onPointerEnter = callback;
}
public setOnPointerCancel(callback: (event: AdaptedEvent) => void): void {
public setOnPointerCancel(callback: PointerEventCallback): void {
this.onPointerCancel = callback;
}
public setOnPointerOutOfBounds(
callback: (event: AdaptedEvent) => void
): void {
public setOnPointerOutOfBounds(callback: PointerEventCallback): void {
this.onPointerOutOfBounds = callback;
}
public setOnPointerMoveOver(callback: (event: AdaptedEvent) => void): void {
public setOnPointerMoveOver(callback: PointerEventCallback): void {
this.onPointerMoveOver = callback;
}
public setOnPointerMoveOut(callback: (event: AdaptedEvent) => void): void {
public setOnPointerMoveOut(callback: PointerEventCallback): void {
this.onPointerMoveOut = callback;
}

Expand Down
4 changes: 4 additions & 0 deletions src/web/tools/GestureHandlerWebDelegate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,5 +151,9 @@ export class GestureHandlerWebDelegate

public destroy(config: Config): void {
this.removeContextMenuListeners(config);

this.eventManagers.forEach((manager) => {
manager.unregisterListeners();
});
}
}
Loading

0 comments on commit baffb68

Please sign in to comment.