Skip to content

Commit 1e1f4e0

Browse files
authored
[Web] Make PointerTracker elements nullable (#3565)
## Description It was reported that in some cases _Gesture Handler_ crashes on web on the following [line](https://github.com/software-mansion/react-native-gesture-handler/blob/a19c683fa2d2849c5ed72f5d85c1ff9528fe8f6f/packages/react-native-gesture-handler/src/web/handlers/GestureHandler.ts#L704). Seems like elements in `PointerTracker` may not exist, even though we believed that during our workflow they always do. Casts in `PointerTracker` were introduced because `Map.get` may return `undefined` if the element doesn't exist. Turns out that it actually may be the case, so we decided to remove those casts and handle these cases across our codebase. While we don't know what exactly causes the fact that elements are not inside `trackedPointers` map, we have two possibilities: 1. Pointer is removed form `PointerTracker` before handler enters `BEGAN` state - removing may happen for example when one lifts pointer from the view (calling `onPointerUp`, etc.). 2. `PointerTracker` is reset before handler enters `BEGAN` state - this one can happen when `pointercancel` event is received. ## Test plan Tested on `expo-example` on `web`
1 parent 36d302e commit 1e1f4e0

File tree

7 files changed

+39
-22
lines changed

7 files changed

+39
-22
lines changed

packages/react-native-gesture-handler/src/web/detectors/RotationGestureDetector.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ export default class RotationGestureDetector
4242
const firstPointerCoords = tracker.getLastAbsoluteCoords(firstPointerID);
4343
const secondPointerCoords = tracker.getLastAbsoluteCoords(secondPointerID);
4444

45+
if (!firstPointerCoords || !secondPointerCoords) {
46+
return;
47+
}
48+
4549
const vectorX: number = secondPointerCoords.x - firstPointerCoords.x;
4650
const vectorY: number = secondPointerCoords.y - firstPointerCoords.y;
4751

packages/react-native-gesture-handler/src/web/handlers/FlingGestureHandler.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ export default class FlingGestureHandler extends GestureHandler {
4949
private tryEndFling(): boolean {
5050
const velocityVector = Vector.fromVelocity(this.tracker, this.keyPointer);
5151

52+
if (!velocityVector) {
53+
return false;
54+
}
55+
5256
const getAlignment = (
5357
direction: Directions | DiagonalDirections,
5458
minimalAlignmentCosine: number

packages/react-native-gesture-handler/src/web/handlers/GestureHandler.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -701,9 +701,15 @@ export default abstract class GestureHandler implements IGestureHandler {
701701
}
702702

703703
const rect = this.delegate.measureView();
704-
const { x, y } = this.tracker.getLastAbsoluteCoords();
705-
const offsetX: number = x - rect.pageX;
706-
const offsetY: number = y - rect.pageY;
704+
705+
const lastCoords = this.tracker.getLastAbsoluteCoords();
706+
707+
if (!lastCoords) {
708+
return false;
709+
}
710+
711+
const offsetX: number = lastCoords.x - rect.pageX;
712+
const offsetY: number = lastCoords.y - rect.pageY;
707713

708714
return (
709715
offsetX >= left && offsetX <= right && offsetY >= top && offsetY <= bottom

packages/react-native-gesture-handler/src/web/handlers/PanGestureHandler.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -226,10 +226,10 @@ export default class PanGestureHandler extends GestureHandler {
226226
}
227227

228228
private updateVelocity(pointerId: number) {
229-
const { x, y } = this.tracker.getVelocity(pointerId);
229+
const velocities = this.tracker.getVelocity(pointerId);
230230

231-
this.velocityX = x;
232-
this.velocityY = y;
231+
this.velocityX = velocities?.x ?? 0;
232+
this.velocityY = velocities?.y ?? 0;
233233
}
234234

235235
// Events Handling

packages/react-native-gesture-handler/src/web/tools/GestureHandlerOrchestrator.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,7 @@ export default class GestureHandlerOrchestrator {
337337
const point = handler.tracker.getLastAbsoluteCoords(pointer);
338338

339339
return (
340+
point &&
340341
handler.delegate.isPointerInBounds(point) &&
341342
otherHandler.delegate.isPointerInBounds(point)
342343
);

packages/react-native-gesture-handler/src/web/tools/PointerTracker.ts

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,9 @@ export default class PointerTracker {
6161
}
6262

6363
public track(event: AdaptedEvent): void {
64-
const element: TrackerElement = this.trackedPointers.get(
65-
event.pointerId
66-
) as TrackerElement;
64+
const pointerData = this.trackedPointers.get(event.pointerId);
6765

68-
if (!element) {
66+
if (!pointerData) {
6967
return;
7068
}
7169

@@ -74,13 +72,13 @@ export default class PointerTracker {
7472
this.velocityTracker.add(event);
7573
const [velocityX, velocityY] = this.velocityTracker.velocity;
7674

77-
element.velocityX = velocityX;
78-
element.velocityY = velocityY;
75+
pointerData.velocityX = velocityX;
76+
pointerData.velocityY = velocityY;
7977

80-
element.abosoluteCoords = { x: event.x, y: event.y };
81-
element.relativeCoords = { x: event.offsetX, y: event.offsetY };
78+
pointerData.abosoluteCoords = { x: event.x, y: event.y };
79+
pointerData.relativeCoords = { x: event.offsetX, y: event.offsetY };
8280

83-
this.trackedPointers.set(event.pointerId, element);
81+
this.trackedPointers.set(event.pointerId, pointerData);
8482

8583
this.cachedAbsoluteAverages = this.getAbsoluteCoordsAverage();
8684
this.cachedRelativeAverages = this.getRelativeCoordsAverage();
@@ -114,20 +112,24 @@ export default class PointerTracker {
114112
}
115113

116114
public getVelocity(pointerId: number) {
117-
return {
118-
x: this.trackedPointers.get(pointerId)?.velocityX as number,
119-
y: this.trackedPointers.get(pointerId)?.velocityY as number,
120-
};
115+
const pointerData = this.trackedPointers.get(pointerId);
116+
117+
return pointerData
118+
? {
119+
x: pointerData.velocityX,
120+
y: pointerData.velocityY,
121+
}
122+
: null;
121123
}
122124

123125
public getLastAbsoluteCoords(pointerId?: number) {
124126
return this.trackedPointers.get(pointerId ?? this.lastMovedPointerId)
125-
?.abosoluteCoords as Point;
127+
?.abosoluteCoords;
126128
}
127129

128130
public getLastRelativeCoords(pointerId?: number) {
129131
return this.trackedPointers.get(pointerId ?? this.lastMovedPointerId)
130-
?.relativeCoords as Point;
132+
?.relativeCoords;
131133
}
132134

133135
// Some handlers use these methods to send average values in native event.

packages/react-native-gesture-handler/src/web/tools/Vector.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ export default class Vector {
2727

2828
static fromVelocity(tracker: PointerTracker, pointerId: number) {
2929
const velocity = tracker.getVelocity(pointerId);
30-
return new Vector(velocity.x, velocity.y);
30+
return velocity ? new Vector(velocity.x, velocity.y) : null;
3131
}
3232

3333
public get magnitude() {

0 commit comments

Comments
 (0)