Skip to content

fix: remove UIPointerInteraction from the view when unbinding the hover handler#4291

Open
petterikorpimaa wants to merge 1 commit into
software-mansion:mainfrom
petterikorpimaa:fix-hover-pointer-interaction-leak
Open

fix: remove UIPointerInteraction from the view when unbinding the hover handler#4291
petterikorpimaa wants to merge 1 commit into
software-mansion:mainfrom
petterikorpimaa:fix-hover-pointer-interaction-leak

Conversation

@petterikorpimaa

Copy link
Copy Markdown

Description

Fixes #4290.

RNHoverGestureHandler adds a UIPointerInteraction to the view in bindToView:, but never actually removes it. In unbindFromView, [super unbindFromView] runs first and detaches the gesture recognizer, which sets self.recognizer.view to nil. The following removeInteraction: call is then a message to nil and does nothing, so the interaction stays on the UIView for the rest of its life.

With Fabric view recycling, that leaked interaction later belongs to an unrelated component. Its delegate (the recognizer) is gone by then, and a UIPointerInteraction without a delegate applies the system default pointer effect over the whole view. The visible result is native hover effects (very prominent with the Liquid Glass style on iPadOS 26) appearing on random elements that never had a hover gesture, accumulating as hover handlers unmount and remount.

This PR captures the view reference before calling [super unbindFromView] and removes the interaction from the captured reference.

Test plan

Tested in an app that uses Gesture.Hover() on most of its toolbar and menu items, on a real iPad (iPadOS 26) with Apple Pencil hover and a trackpad:

  • Before the change: after a few mount/unmount cycles of hover-enabled views, hovering over unrelated elements shows the native hover effect on random views.
  • With the change (applied to the app as a package patch): the stray hover effects no longer appear, and hover gestures keep working as before.
  • The RNGestureHandler pod compiles cleanly with the change.

Copilot AI review requested due to automatic review settings July 2, 2026 05:20

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 an iOS hover interaction leak in RNHoverGestureHandler by ensuring the UIPointerInteraction added in bindToView: is reliably removed during unbindFromView, preventing stray system hover effects on Fabric-recycled views.

Changes:

  • Capture the bound UIView reference before calling [super unbindFromView] (which clears recognizer.view).
  • Remove _pointerInteraction from the captured view instead of from self.recognizer.view after it becomes nil.

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

@petterikorpimaa petterikorpimaa force-pushed the fix-hover-pointer-interaction-leak branch from ed75cd7 to 5ec9f49 Compare July 2, 2026 05:37
@petterikorpimaa

Copy link
Copy Markdown
Author

Standalone repro, with results detailed in #4290: https://github.com/petterikorpimaa/rngh-hover-leak-repro

Verified this fix against it on a real iPad (iPadOS 26, RN 0.86.0, RNGH 2.32.0). Without the fix: a deterministic three-tap repro shows the leaked native hover effect on a still-mounted view, recycled views spread it to unrelated components, and unmounting a poisoned view after hovering it aborts the app in a Fabric assertion (unmountChildComponentView:index:). With the fix: hover callbacks keep working, no stray native hover effects, no crash.

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.

Hover handler never removes its UIPointerInteraction on unbind, leaking hover effects onto recycled views (iOS)

2 participants