From 5df3d3cc1392e716d5d327cbfb6de3b2f530ac31 Mon Sep 17 00:00:00 2001 From: Krzysztof Piaskowy Date: Fri, 9 May 2025 17:57:02 +0200 Subject: [PATCH] Fix ref management --- src/handlers/gestures/GestureDetector/Wrap.tsx | 6 +++++- src/handlers/gestures/GestureDetector/index.tsx | 16 +++++++++++++--- .../GestureDetector/useViewRefHandler.ts | 13 +++++++++++-- 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/src/handlers/gestures/GestureDetector/Wrap.tsx b/src/handlers/gestures/GestureDetector/Wrap.tsx index 06c79267d0..564008c3a6 100644 --- a/src/handlers/gestures/GestureDetector/Wrap.tsx +++ b/src/handlers/gestures/GestureDetector/Wrap.tsx @@ -6,6 +6,7 @@ export class Wrap extends React.Component<{ onGestureHandlerEvent?: unknown; // Implicit `children` prop has been removed in @types/react^18.0.0 children?: React.ReactNode; + reanimatedContext?: { current: number }; }> { render() { try { @@ -17,7 +18,10 @@ export class Wrap extends React.Component<{ const child: any = React.Children.only(this.props.children); return React.cloneElement( child, - { collapsable: false }, + { + collapsable: false, + reanimatedContext: this.props.reanimatedContext, + }, // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access child.props.children ); diff --git a/src/handlers/gestures/GestureDetector/index.tsx b/src/handlers/gestures/GestureDetector/index.tsx index 71f9dd2948..c03cc73e25 100644 --- a/src/handlers/gestures/GestureDetector/index.tsx +++ b/src/handlers/gestures/GestureDetector/index.tsx @@ -1,5 +1,6 @@ /* eslint-disable react/no-unused-prop-types */ import React, { + Ref, useContext, useEffect, useLayoutEffect, @@ -114,7 +115,10 @@ export const GestureDetector = (props: GestureDetectorProps) => { const webEventHandlersRef = useWebEventHandlers(); // Store state in ref to prevent unnecessary renders - const state = useRef({ + const state = useRef< + GestureDetectorState + & { viewRef: { props: { reanimatedContext?: { current: number } } } | null } + >({ firstRender: true, viewRef: null, previousViewTag: -1, @@ -150,7 +154,13 @@ export const GestureDetector = (props: GestureDetectorProps) => { useAnimatedGesture(preparedGesture, needsToRebuildReanimatedEvent); useLayoutEffect(() => { - const viewTag = findNodeHandle(state.viewRef) as number; + let viewTag = -1; + const reanimatedContext = state.viewRef?.props.reanimatedContext; + if (reanimatedContext && reanimatedContext.current > 0) { + viewTag = reanimatedContext.current; + } else { + viewTag = findNodeHandle(state.viewRef) as number; + } preparedGesture.isMounted = true; attachHandlers({ @@ -186,6 +196,6 @@ export const GestureDetector = (props: GestureDetectorProps) => { ); } else { - return {props.children}; + return }>{props.children}; } }; diff --git a/src/handlers/gestures/GestureDetector/useViewRefHandler.ts b/src/handlers/gestures/GestureDetector/useViewRefHandler.ts index 10679000c6..80a1b6e4b5 100644 --- a/src/handlers/gestures/GestureDetector/useViewRefHandler.ts +++ b/src/handlers/gestures/GestureDetector/useViewRefHandler.ts @@ -9,6 +9,10 @@ declare const global: { isViewFlatteningDisabled: (node: unknown) => boolean | null; // JSI function }; +type Props = { + reanimatedContext?: { current: number }, +} + // Ref handler for the Wrap component attached under the GestureDetector. // It's responsible for setting the viewRef on the state and triggering the reattaching of handlers // if the view has changed. @@ -17,7 +21,7 @@ export function useViewRefHandler( updateAttachedGestures: (skipConfigUpdate?: boolean) => void ) { const refHandler = useCallback( - (ref: React.Component | null) => { + (ref: (React.Component)) => { if (ref === null) { return; } @@ -26,7 +30,12 @@ export function useViewRefHandler( // if it's the first render, also set the previousViewTag to prevent reattaching gestures when not needed if (state.previousViewTag === -1) { - state.previousViewTag = findNodeHandle(state.viewRef) as number; + const reanimatedContext = ref.props.reanimatedContext; + if (reanimatedContext && reanimatedContext.current > 0) { + state.previousViewTag = reanimatedContext.current; + } else { + state.previousViewTag = findNodeHandle(state.viewRef) as number; + } } // Pass true as `skipConfigUpdate`. Here we only want to trigger the eventual reattaching of handlers