Skip to content

[Web] Don't call cancel on unregistered handlers - #4134

Merged
j-piasecki merged 4 commits into
mainfrom
@jpiasecki/web-gate-pointer-cancel
Apr 30, 2026
Merged

[Web] Don't call cancel on unregistered handlers#4134
j-piasecki merged 4 commits into
mainfrom
@jpiasecki/web-gate-pointer-cancel

Conversation

@j-piasecki

Copy link
Copy Markdown
Member

Description

On web, it was possible for a handler to get canceled twice: once by some internal condition, and once by pointercancel event. The first time was handled correctly, since the orchestrator tracked the gesture, and it was reset correctly after being canceled. The second time, the gesture was untracked after being reset and it was canceled "in the void" and it was kept in the canceled state until it was registered again, which allowed it to be cleaned properly.

It's easy to reproduce with a Touchable inside a ScrollView and starting to scroll near the very edge of the touchable. The first cancel happens when the pointer moves out of the touchable before the scroll starts, and the second one is caused by the scroll starting.

This PR changes the behavior so that handlers need to be registered in the orchestrator before being canceled.

Test plan

Before After
Screen.Recording.2026-04-29.at.14.55.16.mov
Screen.Recording.2026-04-29.at.14.54.51.mov

j-piasecki and others added 2 commits April 29, 2026 14:52
Co-authored-by: Copilot <copilot@github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes a web-specific edge case where a gesture handler could be cancelled twice (once while tracked by the orchestrator and then again via a later pointercancel), causing the second cancel to occur after the handler had already been untracked/reset and leaving it stuck in CANCELLED until re-registered.

Changes:

  • Add an orchestrator helper to check whether a handler is currently recorded.
  • Guard onPointerCancel so cancel() is only invoked when the handler is still registered in the orchestrator.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
packages/react-native-gesture-handler/src/web/tools/GestureHandlerOrchestrator.ts Adds isHandlerRecorded() to allow callers to verify orchestrator registration before attempting cancellation.
packages/react-native-gesture-handler/src/web/handlers/GestureHandler.ts Prevents pointercancel from calling cancel() on handlers that are no longer tracked by the orchestrator.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@m-bert m-bert left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we could also use it in recordHandlerIfNotPresent?

Base automatically changed from @jpiasecki/remove-explicit-reset-on-cancel to main April 30, 2026 09:43
@j-piasecki
j-piasecki merged commit c415c99 into main Apr 30, 2026
2 checks passed
@j-piasecki
j-piasecki deleted the @jpiasecki/web-gate-pointer-cancel branch April 30, 2026 10:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants