Skip to content

[General] Fix gestures becoming unresponsive after a fast refresh#4096

Open
j-piasecki wants to merge 1 commit intomainfrom
@jpiasecki/fix-fast-refresh
Open

[General] Fix gestures becoming unresponsive after a fast refresh#4096
j-piasecki wants to merge 1 commit intomainfrom
@jpiasecki/fix-fast-refresh

Conversation

@j-piasecki
Copy link
Copy Markdown
Member

@j-piasecki j-piasecki commented Apr 17, 2026

Description

Fast refresh was able to make gestures unresponsive - Gesture Handler uses useMemo to store the handler tag, which gets invalidated on the fast refresh. Reanimated's useHandler/useEvent preserves their internal state, and the worklet event handler didn't rebuild. This caused a gesture with a new tag to use the event handler built for the previous tag, which was ignoring all incoming events.

This PR fixes this by tracking handler tag changes and rebuilding the event handler when it changes.

Supersedes #3997

Test plan

File1.tsx
import React from 'react';
import { View } from 'react-native';
import { GestureDetector, useTapGesture } from 'react-native-gesture-handler';

function Test() {
  const gesture = useTapGesture({
    onActivate: () => {
      console.log('onActivate');
    },
  });

  const COMMENT_THIS = 2;

  return (
    <GestureDetector gesture={gesture}>
      <View style={{ width: 100, height: 100, backgroundColor: 'red' }} />
    </GestureDetector>
  );
}

export default Test;
File2.tsx
import React from 'react';
import { GestureHandlerRootView } from 'react-native-gesture-handler';

import Test from './File1';

function Example() {
  return (
    <GestureHandlerRootView>
      <Test />
    </GestureHandlerRootView>
  );
}

export default Example;
  1. Navigate to File2
  2. Verify that tap works
  3. Comment COMMENT_THIS and save File1
  4. Check whether the tap works

Copilot AI review requested due to automatic review settings April 17, 2026 10:32
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

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 Fast Refresh regression where Reanimated gesture worklet event handlers could become stale and ignore events after a regenerated handlerTag.

Changes:

  • Track handlerTag changes via useRef + useEffect to detect post-refresh tag regeneration.
  • Force Reanimated.useEvent to rebuild the worklet event handler when the handlerTag changes.
  • Deduplicate the Reanimated event names into a shared constant.

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

Comment on lines 82 to 86
const reanimatedEvent = Reanimated?.useEvent(
callback,
[
'onGestureHandlerReanimatedEvent',
'onGestureHandlerReanimatedStateChange',
'onGestureHandlerReanimatedTouchEvent',
],
!!reanimatedHandler?.doDependenciesDiffer
REANIMATED_EVENT_NAMES,
handlerTagChanged || !!reanimatedHandler?.doDependenciesDiffer
);
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

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

Consider adding a unit test for this regression by mocking Reanimated.useEvent and asserting the third argument (rebuild) flips to true when handlerTag changes between renders (simulating Fast Refresh preserving refs). This would prevent future changes from reintroducing the stale-closure issue.

Copilot uses AI. Check for mistakes.
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.

2 participants