Skip to content

Fix native gesture reattach #3672

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: next
Choose a base branch
from

Conversation

akwasniewski
Copy link
Contributor

Description

In NativeDetector native gesture failed to reattach when child changed.

Test plan

Add a logging message in attach/detach in android/.../react/RNGestureHandlerRegistry.kt and apple/RNGestureHandlerRegistry.m
`

import * as React from 'react';
import { StyleSheet, Text, View, ScrollView, Button } from 'react-native';
import {
  GestureHandlerRootView,
  NativeDetector,
  useGesture,
} from 'react-native-gesture-handler';

export default function App() {
  const items = Array.from({ length: 5 }, (_, index) => `Item ${index + 1}`);
  const [enabled, setEnabled] = React.useState(true);
  const gesture = useGesture('NativeViewGestureHandler', {
    onBegin: (e) => {
      console.log('onBegin');
    },
    onStart: (e) => {
      console.log('onStart');
    }
  });

  const SV1 = () => (
    <ScrollView style={styles.scrollView1}>
      {items.map((item, index) => (
        <View key={index} style={styles.item}>
          <Text style={styles.text}>{item}</Text>
        </View>
      ))}
    </ScrollView>
  );

  const SV2 = () => (
    <ScrollView style={styles.scrollView2}>
      {items.map((item, index) => (
        <View key={index} style={styles.item}>
          <Text style={styles.text}>{item}</Text>
        </View>
      ))}
    </ScrollView>
  );

  return (
    <GestureHandlerRootView
      style={{ flex: 1, backgroundColor: 'white', paddingTop: 100 }}>
      <Button
        title="Swap the child"
        onPress={() => {
          setEnabled(!enabled);
        }}
      />
      <NativeDetector gesture={gesture}>
        {enabled ? <SV1 /> : <SV2 />}
      </NativeDetector >
    </GestureHandlerRootView >
  );
}

const styles = StyleSheet.create({
  scrollView1: {
    backgroundColor: 'pink',
    marginHorizontal: 20,
  },
  scrollView2: {
    backgroundColor: 'lightblue',
    marginHorizontal: 20,
  },

  item: {
    flexDirection: 'row',
    justifyContent: 'center',
    alignItems: 'center',
    padding: 20,
    margin: 2,
    backgroundColor: 'white',
    borderRadius: 10,
  },
  text: {
    fontSize: 20,
    color: 'black',
  },
});

@akwasniewski akwasniewski marked this pull request as ready for review August 12, 2025 09:46
@akwasniewski akwasniewski changed the title @akwasniewski/fix native gesture reattach Fix native gesture reattach Aug 12, 2025
@akwasniewski akwasniewski requested a review from m-bert August 12, 2025 10:36
Copy link
Contributor

@m-bert m-bert left a comment

Choose a reason for hiding this comment

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

I can see that android got a bit "out of sync" with iOS, can we make it so that one is analogous to another?

@@ -152,7 +154,8 @@ - (void)updateProps:(const Props::Shared &)propsBase oldProps:(const Props::Shar

if (handlerChange.second == RNGestureHandlerMutationAttach) {
if ([self shouldAttachGestureToSubview:handlerTag]) {
[_nativeHandlersToAttach addObject:handlerTag];
[_attachedNativeHandlers addObject:handlerTag];
Copy link
Contributor

Choose a reason for hiding this comment

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

Why don't we move this into tryAttachHandlerToChildView?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is intentional, as tryAttachHandlerToChildView is also used in didAddSubview. attachedNativeHandlers is intentionally not cleaned on reattach, thus there is no need to call addObject again.

Comment on lines 99 to 101
for (const id handlerTag : _attachedNativeHandlers) {
[self tryAttachHandlerToChildView:handlerTag];
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Why was this loop moved outside of tryAttachHandlerToChildView?

Also we could find better name for this method, like tryAttachNativeHandlersToChildView

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done for ios and android.

@@ -102,24 +103,20 @@ class RNGestureHandlerDetectorView(context: Context) : ReactViewGroup(context) {
val registry = RNGestureHandlerModule.registries[moduleId]
?: throw Exception("Tried to access a non-existent registry")

for (tag in nativeHandlersToAttach) {
for (tag in attachedNativeHandlers) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe a cosmetic note, but I don't like that we iterate through attachedNativeHandlers and call attachHandlerToView - it looks like we try to attach it again, which is not the case.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I changed the variable name to nativeHandlers

@akwasniewski akwasniewski requested a review from m-bert August 18, 2025 11:16
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