From 5ffa47792ff4ed565b8aae61e03d9297c7328798 Mon Sep 17 00:00:00 2001 From: Krzysztof Piaskowy Date: Wed, 4 Dec 2024 11:09:40 +0100 Subject: [PATCH] Refactor findNodeHandler (#6736) ## Summary This PR addresses the issue reported at [https://github.com/software-mansion/react-native-reanimated/issues/6719](https://github.com/software-mansion/react-native-reanimated/issues/6719) and aims to: - **Unify the method used to obtain the view tag**, as there are currently several approaches. - **Avoid passing a class component to the findNodeHandler**. Instead, we'll pass a ref to the component, similar to what Expo implemented here: [https://github.com/expo/expo/pull/33016](https://github.com/expo/expo/pull/33016). - **Limit unnecessary invocations of findNodeHandler** to no more than one call per render. - **Remove the invocation of findHostInstance from Paper renderer** on the New Architecture. **Additional Remarks:** - When a class component is passed to `createAnimatedComponent`, it will still fall back to the slow path where we can get a native ref. - In `NativeEventManager`, we need to call findNodeHandler again after every render to ensure that the children of `` haven't changed their native tags. - `LayoutAnimationConfig` still uses findNodeHandler. It requires a complete refactor of their functionality to eliminate its use, and I plan to handle this in another PR. - `findHostInstance_DEPRECATED` always follows the slow path even for native refs, which is why I've implemented our own version of `findHostInstance` to optimize the happy path. Fixes https://github.com/software-mansion/react-native-reanimated/issues/6719 Related PRs: - https://github.com/software-mansion/react-native-reanimated/pull/6030 - https://github.com/software-mansion/react-native-reanimated/pull/5960 - https://github.com/software-mansion/react-native-reanimated/pull/4445 - https://github.com/expo/expo/pull/33016 ## Test plan - [x] check Paper - [x] check Fabric - [x] check Web --- .../createAnimatedComponent/JSPropsUpdater.ts | 8 +- .../NativeEventsManager.ts | 57 +++++++-- .../createAnimatedComponent/commonTypes.ts | 12 +- .../createAnimatedComponent.tsx | 111 +++++++++--------- .../src/fabricUtils.ts | 24 ++-- .../src/platform-specific/RNRenderer.ts | 4 - .../src/platform-specific/RNRenderer.web.ts | 4 - .../src/platform-specific/findHostInstance.ts | 77 ++++++++++++ .../platform-specific/findHostInstance.web.ts | 3 + 9 files changed, 198 insertions(+), 102 deletions(-) delete mode 100644 packages/react-native-reanimated/src/platform-specific/RNRenderer.ts delete mode 100644 packages/react-native-reanimated/src/platform-specific/RNRenderer.web.ts create mode 100644 packages/react-native-reanimated/src/platform-specific/findHostInstance.ts create mode 100644 packages/react-native-reanimated/src/platform-specific/findHostInstance.web.ts diff --git a/packages/react-native-reanimated/src/createAnimatedComponent/JSPropsUpdater.ts b/packages/react-native-reanimated/src/createAnimatedComponent/JSPropsUpdater.ts index f0bd87da036..70e345b73df 100644 --- a/packages/react-native-reanimated/src/createAnimatedComponent/JSPropsUpdater.ts +++ b/packages/react-native-reanimated/src/createAnimatedComponent/JSPropsUpdater.ts @@ -38,7 +38,7 @@ class JSPropsUpdaterPaper implements IJSPropsUpdater { > & IAnimatedComponentInternal ) { - const viewTag = animatedComponent._componentViewTag; + const viewTag = animatedComponent.getComponentViewTag(); JSPropsUpdaterPaper._tagToComponentMapping.set(viewTag, animatedComponent); if (JSPropsUpdaterPaper._tagToComponentMapping.size === 1) { const listener = (data: ListenerData) => { @@ -60,7 +60,7 @@ class JSPropsUpdaterPaper implements IJSPropsUpdater { > & IAnimatedComponentInternal ) { - const viewTag = animatedComponent._componentViewTag; + const viewTag = animatedComponent.getComponentViewTag(); JSPropsUpdaterPaper._tagToComponentMapping.delete(viewTag); if (JSPropsUpdaterPaper._tagToComponentMapping.size === 0) { this._reanimatedEventEmitter.removeAllListeners( @@ -100,7 +100,7 @@ class JSPropsUpdaterFabric implements IJSPropsUpdater { if (!JSPropsUpdaterFabric.isInitialized) { return; } - const viewTag = animatedComponent._componentViewTag; + const viewTag = animatedComponent.getComponentViewTag(); JSPropsUpdaterFabric._tagToComponentMapping.set(viewTag, animatedComponent); } @@ -113,7 +113,7 @@ class JSPropsUpdaterFabric implements IJSPropsUpdater { if (!JSPropsUpdaterFabric.isInitialized) { return; } - const viewTag = animatedComponent._componentViewTag; + const viewTag = animatedComponent.getComponentViewTag(); JSPropsUpdaterFabric._tagToComponentMapping.delete(viewTag); } } diff --git a/packages/react-native-reanimated/src/createAnimatedComponent/NativeEventsManager.ts b/packages/react-native-reanimated/src/createAnimatedComponent/NativeEventsManager.ts index da0bbb03b23..e912ae2eca8 100644 --- a/packages/react-native-reanimated/src/createAnimatedComponent/NativeEventsManager.ts +++ b/packages/react-native-reanimated/src/createAnimatedComponent/NativeEventsManager.ts @@ -39,7 +39,7 @@ export class NativeEventsManager implements INativeEventsManager { public updateEvents( prevProps: AnimatedComponentProps ) { - const computedEventTag = this.getEventViewTag(); + const computedEventTag = this.getEventViewTag(true); // If the event view tag changes, we need to completely re-mount all events if (this.#eventViewTag !== computedEventTag) { // Remove all bindings from previous props that ran on the old viewTag @@ -77,23 +77,54 @@ export class NativeEventsManager implements INativeEventsManager { }); } - private getEventViewTag() { + private getEventViewTag(componentUpdate: boolean = false) { // Get the tag for registering events - since the event emitting view can be nested inside the main component const componentAnimatedRef = this.#managedComponent - ._component as AnimatedComponentRef; - let newTag: number; + ._componentRef as AnimatedComponentRef & { + // Fabric + __nativeTag?: number; + // Paper + _nativeTag?: number; + }; if (componentAnimatedRef.getScrollableNode) { + /* + In most cases, getScrollableNode() returns a view tag, and findNodeHandle is not required. + However, to cover more exotic list cases, we will continue to use findNodeHandle + for consistency. For numerical values, findNodeHandle should return the value immediately, + as documented here: https://github.com/facebook/react/blob/91061073d57783c061889ac6720ef1ab7f0c2149/packages/react-native-renderer/src/ReactNativePublicCompat.js#L113 + */ const scrollableNode = componentAnimatedRef.getScrollableNode(); - newTag = findNodeHandle(scrollableNode) ?? -1; - } else { - newTag = - findNodeHandle( - this.#componentOptions?.setNativeProps - ? this.#managedComponent - : componentAnimatedRef - ) ?? -1; + if (typeof scrollableNode === 'number') { + return scrollableNode; + } + return findNodeHandle(scrollableNode) ?? -1; + } + if (this.#componentOptions?.setNativeProps) { + // This case ensures backward compatibility with components that + // have their own setNativeProps method passed as an option. + return findNodeHandle(this.#managedComponent) ?? -1; + } + if (!componentUpdate) { + // On the first render of a component, we may already receive a resolved view tag. + return this.#managedComponent.getComponentViewTag(); + } + if (componentAnimatedRef.__nativeTag || componentAnimatedRef._nativeTag) { + /* + Fast path for native refs, + _nativeTag is used by Paper components, + __nativeTag is used by Fabric components. + */ + return ( + componentAnimatedRef.__nativeTag ?? + componentAnimatedRef._nativeTag ?? + -1 + ); } - return newTag; + /* + When a component is updated, a child could potentially change and have a different + view tag. This can occur with a GestureDetector component. + */ + return findNodeHandle(componentAnimatedRef) ?? -1; } } diff --git a/packages/react-native-reanimated/src/createAnimatedComponent/commonTypes.ts b/packages/react-native-reanimated/src/createAnimatedComponent/commonTypes.ts index edb1c867c23..d48b3d771f4 100644 --- a/packages/react-native-reanimated/src/createAnimatedComponent/commonTypes.ts +++ b/packages/react-native-reanimated/src/createAnimatedComponent/commonTypes.ts @@ -100,15 +100,10 @@ export interface AnimatedComponentRef extends Component { export interface IAnimatedComponentInternal { _styles: StyleProps[] | null; _animatedProps?: Partial>; - /** - * Used for Shared Element Transitions, Layout Animations and Animated Styles. - * It is not related to event handling. - */ - _componentViewTag: number; _isFirstRender: boolean; jestInlineStyle: NestedArray | undefined; jestAnimatedStyle: { value: StyleProps }; - _component: AnimatedComponentRef | HTMLElement | null; + _componentRef: AnimatedComponentRef | HTMLElement | null; _sharedElementTransition: SharedTransition | null; _jsPropsUpdater: IJSPropsUpdater; _InlinePropManager: IInlinePropManager; @@ -117,6 +112,11 @@ export interface IAnimatedComponentInternal { _NativeEventsManager?: INativeEventsManager; _viewInfo?: ViewInfo; context: React.ContextType; + /** + * Used for Shared Element Transitions, Layout Animations and Animated Styles. + * It is not related to event handling. + */ + getComponentViewTag: () => number; } export type NestedArray = T | NestedArray[]; diff --git a/packages/react-native-reanimated/src/createAnimatedComponent/createAnimatedComponent.tsx b/packages/react-native-reanimated/src/createAnimatedComponent/createAnimatedComponent.tsx index 9750bb853d6..762e2693bdc 100644 --- a/packages/react-native-reanimated/src/createAnimatedComponent/createAnimatedComponent.tsx +++ b/packages/react-native-reanimated/src/createAnimatedComponent/createAnimatedComponent.tsx @@ -8,11 +8,10 @@ import type { } from 'react'; import React from 'react'; import { Platform } from 'react-native'; -import { findNodeHandle } from '../platformFunctions/findNodeHandle'; import '../layoutReanimation/animationsManager'; import invariant from 'invariant'; import { adaptViewConfig } from '../ConfigHelper'; -import { RNRenderer } from '../platform-specific/RNRenderer'; +import { findHostInstance } from '../platform-specific/findHostInstance'; import { enableLayoutAnimations } from '../core'; import { SharedTransition } from '../layoutReanimation'; import { LayoutAnimationType } from '../commonTypes'; @@ -125,11 +124,10 @@ export function createAnimatedComponent( { _styles: StyleProps[] | null = null; _animatedProps?: Partial>; - _componentViewTag = -1; _isFirstRender = true; jestInlineStyle: NestedArray | undefined; jestAnimatedStyle: { value: StyleProps } = { value: {} }; - _component: AnimatedComponentRef | HTMLElement | null = null; + _componentRef: AnimatedComponentRef | HTMLElement | null = null; _sharedElementTransition: SharedTransition | null = null; _jsPropsUpdater = new JSPropsUpdater(); _InlinePropManager = new InlinePropManager(); @@ -157,7 +155,6 @@ export function createAnimatedComponent( } componentDidMount() { - this._componentViewTag = this._getComponentViewTag(); if (!IS_WEB) { // It exists only on native platforms. We initialize it here because the ref to the animated component is available only post-mount this._NativeEventsManager = new NativeEventsManager(this, options); @@ -174,7 +171,7 @@ export function createAnimatedComponent( if (IS_WEB) { if (this.props.exiting) { - saveSnapshot(this._component as HTMLElement); + saveSnapshot(this._componentRef as HTMLElement); } if ( @@ -190,11 +187,11 @@ export function createAnimatedComponent( if (!skipEntering) { startWebLayoutAnimation( this.props, - this._component as ReanimatedHTMLElement, + this._componentRef as ReanimatedHTMLElement, LayoutAnimationType.ENTERING ); } else { - (this._component as HTMLElement).style.visibility = 'initial'; + (this._componentRef as HTMLElement).style.visibility = 'initial'; } } @@ -210,7 +207,7 @@ export function createAnimatedComponent( this._configureSharedTransition(true); } this._sharedElementTransition?.unregisterTransition( - this._componentViewTag, + this.getComponentViewTag(), true ); @@ -218,7 +215,7 @@ export function createAnimatedComponent( if ( IS_WEB && - this._component && + this._componentRef && exiting && !getReducedMotionFromConfig(exiting as CustomConfig) ) { @@ -226,7 +223,7 @@ export function createAnimatedComponent( startWebLayoutAnimation( this.props, - this._component as ReanimatedHTMLElement, + this._componentRef as ReanimatedHTMLElement, LayoutAnimationType.EXITING ); } else if (exiting && !IS_WEB && !isFabric()) { @@ -237,7 +234,7 @@ export function createAnimatedComponent( : getReduceMotionFromConfig(); if (!reduceMotionInExiting) { updateLayoutAnimations( - this._componentViewTag, + this.getComponentViewTag(), LayoutAnimationType.EXITING, maybeBuild( exiting, @@ -249,31 +246,33 @@ export function createAnimatedComponent( } } - _getComponentViewTag() { + getComponentViewTag() { return this._getViewInfo().viewTag as number; } _detachStyles() { - if (this._componentViewTag !== -1 && this._styles !== null) { + const viewTag = this.getComponentViewTag(); + if (viewTag !== -1 && this._styles !== null) { for (const style of this._styles) { - style.viewDescriptors.remove(this._componentViewTag); + style.viewDescriptors.remove(viewTag); } if (this.props.animatedProps?.viewDescriptors) { - this.props.animatedProps.viewDescriptors.remove( - this._componentViewTag - ); + this.props.animatedProps.viewDescriptors.remove(viewTag); } if (isFabric()) { - removeFromPropsRegistry(this._componentViewTag); + removeFromPropsRegistry(viewTag); } } } _updateFromNative(props: StyleProps) { if (options?.setNativeProps) { - options.setNativeProps(this._component as AnimatedComponentRef, props); + options.setNativeProps( + this._componentRef as AnimatedComponentRef, + props + ); } else { - (this._component as AnimatedComponentRef)?.setNativeProps?.(props); + (this._componentRef as AnimatedComponentRef)?.setNativeProps?.(props); } } @@ -286,24 +285,22 @@ export function createAnimatedComponent( let viewName: string | null; let shadowNodeWrapper: ShadowNodeWrapper | null = null; let viewConfig; - // Component can specify ref which should be animated when animated version of the component is created. - // Otherwise, we animate the component itself. - const component = (this._component as AnimatedComponentRef) - ?.getAnimatableRef - ? (this._component as AnimatedComponentRef).getAnimatableRef?.() - : this; if (SHOULD_BE_USE_WEB) { // At this point I assume that `_setComponentRef` was already called and `_component` is set. // `this._component` on web represents HTMLElement of our component, that's why we use casting - viewTag = this._component as HTMLElement; + viewTag = this._componentRef as HTMLElement; viewName = null; shadowNodeWrapper = null; viewConfig = null; } else { - // hostInstance can be null for a component that doesn't render anything (render function returns null). Example: svg Stop: https://github.com/react-native-svg/react-native-svg/blob/develop/src/elements/Stop.tsx - const hostInstance = RNRenderer.findHostInstance_DEPRECATED(component); + const hostInstance = findHostInstance(this); if (!hostInstance) { + /* + findHostInstance can return null for a component that doesn't render anything + (render function returns null). Example: + svg Stop: https://github.com/react-native-svg/react-native-svg/blob/develop/src/elements/Stop.tsx + */ throw new ReanimatedError( 'Cannot find host instance for this component. Maybe it renders nothing?' ); @@ -314,7 +311,7 @@ export function createAnimatedComponent( viewName = viewInfo.viewName; viewConfig = viewInfo.viewConfig; shadowNodeWrapper = isFabric() - ? getShadowNodeWrapperFromRef(this) + ? getShadowNodeWrapperFromRef(this, hostInstance) : null; } this._viewInfo = { viewTag, viewName, shadowNodeWrapper, viewConfig }; @@ -341,8 +338,6 @@ export function createAnimatedComponent( adaptViewConfig(viewConfig); } - this._componentViewTag = viewTag as number; - // remove old styles if (prevStyles) { // in most of the cases, views have only a single animated style and it remains unchanged @@ -422,7 +417,7 @@ export function createAnimatedComponent( this._InlinePropManager.attachInlineProps(this, this._getViewInfo()); if (IS_WEB && this.props.exiting) { - saveSnapshot(this._component as HTMLElement); + saveSnapshot(this._componentRef as HTMLElement); } // Snapshot won't be undefined because it comes from getSnapshotBeforeUpdate method @@ -434,7 +429,7 @@ export function createAnimatedComponent( ) { tryActivateLayoutTransition( this.props, - this._component as ReanimatedHTMLElement, + this._componentRef as ReanimatedHTMLElement, snapshot ); } @@ -453,7 +448,7 @@ export function createAnimatedComponent( ) : undefined; updateLayoutAnimations( - this._componentViewTag, + this.getComponentViewTag(), LayoutAnimationType.LAYOUT, layout ); @@ -467,7 +462,7 @@ export function createAnimatedComponent( const { sharedTransitionTag } = this.props; if (!sharedTransitionTag) { this._sharedElementTransition?.unregisterTransition( - this._componentViewTag, + this.getComponentViewTag(), isUnmounting ); this._sharedElementTransition = null; @@ -478,34 +473,42 @@ export function createAnimatedComponent( this._sharedElementTransition ?? new SharedTransition(); sharedElementTransition.registerTransition( - this._componentViewTag, + this.getComponentViewTag(), sharedTransitionTag, isUnmounting ); this._sharedElementTransition = sharedElementTransition; } + _resolveComponentRef = (ref: Component | HTMLElement | null) => { + const componentRef = ref as AnimatedComponentRef; + // Component can specify ref which should be animated when animated version of the component is created. + // Otherwise, we animate the component itself. + if (componentRef && componentRef.getAnimatableRef) { + return componentRef.getAnimatableRef(); + } + return componentRef; + }; + _setComponentRef = setAndForwardRef({ getForwardedRef: () => this.props.forwardedRef as MutableRefObject< Component, Record, unknown> >, setLocalRef: (ref) => { - // TODO update config - - const tag = findNodeHandle(ref as Component); - - // callback refs are executed twice - when the component mounts with ref, - // and with null when it unmounts - if (tag !== null) { - this._componentViewTag = tag; + if (!ref) { + // component has been unmounted + return; + } + if (ref !== this._componentRef) { + this._componentRef = this._resolveComponentRef(ref); + // if ref is changed, reset viewInfo + this._viewInfo = undefined; } + const tag = this.getComponentViewTag(); const { layout, entering, exiting, sharedTransitionTag } = this.props; - if ( - (layout || entering || exiting || sharedTransitionTag) && - tag != null - ) { + if (layout || entering || exiting || sharedTransitionTag) { if (!SHOULD_BE_USE_WEB) { enableLayoutAnimations(true, false); } @@ -545,10 +548,6 @@ export function createAnimatedComponent( ); } } - - if (ref !== this._component) { - this._component = ref; - } }, }); @@ -558,9 +557,9 @@ export function createAnimatedComponent( getSnapshotBeforeUpdate() { if ( IS_WEB && - (this._component as HTMLElement)?.getBoundingClientRect !== undefined + (this._componentRef as HTMLElement)?.getBoundingClientRect !== undefined ) { - return (this._component as HTMLElement).getBoundingClientRect(); + return (this._componentRef as HTMLElement).getBoundingClientRect(); } return null; diff --git a/packages/react-native-reanimated/src/fabricUtils.ts b/packages/react-native-reanimated/src/fabricUtils.ts index a872b9a2167..e6eff46e125 100644 --- a/packages/react-native-reanimated/src/fabricUtils.ts +++ b/packages/react-native-reanimated/src/fabricUtils.ts @@ -2,25 +2,19 @@ /* eslint-disable */ import type { ShadowNodeWrapper } from './commonTypes'; +import { + findHostInstance, + HostInstance, +} from './platform-specific/findHostInstance'; -let findHostInstance_DEPRECATED: (ref: unknown) => void; let getInternalInstanceHandleFromPublicInstance: (ref: unknown) => { stateNode: { node: unknown }; }; export function getShadowNodeWrapperFromRef( - ref: React.Component + ref: React.Component, + hostInstance?: HostInstance ): ShadowNodeWrapper { - // load findHostInstance_DEPRECATED lazily because it may not be available before render - if (findHostInstance_DEPRECATED === undefined) { - try { - findHostInstance_DEPRECATED = - require('react-native/Libraries/Renderer/shims/ReactFabric').findHostInstance_DEPRECATED; - } catch (e) { - findHostInstance_DEPRECATED = (_ref: unknown) => null; - } - } - if (getInternalInstanceHandleFromPublicInstance === undefined) { try { getInternalInstanceHandleFromPublicInstance = @@ -50,9 +44,9 @@ export function getShadowNodeWrapperFromRef( } else if (textInputRef) { resolvedRef = textInputRef; } else { - resolvedRef = getInternalInstanceHandleFromPublicInstance( - findHostInstance_DEPRECATED(ref) - ).stateNode.node; + const instance = hostInstance ?? findHostInstance(ref); + resolvedRef = + getInternalInstanceHandleFromPublicInstance(instance).stateNode.node; } return resolvedRef; diff --git a/packages/react-native-reanimated/src/platform-specific/RNRenderer.ts b/packages/react-native-reanimated/src/platform-specific/RNRenderer.ts deleted file mode 100644 index cc5c78a5005..00000000000 --- a/packages/react-native-reanimated/src/platform-specific/RNRenderer.ts +++ /dev/null @@ -1,4 +0,0 @@ -// eslint-disable-next-line @typescript-eslint/ban-ts-comment -// @ts-nocheck -'use strict'; -export { default as RNRenderer } from 'react-native/Libraries/Renderer/shims/ReactNative'; diff --git a/packages/react-native-reanimated/src/platform-specific/RNRenderer.web.ts b/packages/react-native-reanimated/src/platform-specific/RNRenderer.web.ts deleted file mode 100644 index f95b74d4322..00000000000 --- a/packages/react-native-reanimated/src/platform-specific/RNRenderer.web.ts +++ /dev/null @@ -1,4 +0,0 @@ -'use strict'; -// RNRender is not used for web. An export is still defined to eliminate warnings from bundlers such as esbuild. -const RNRenderer = {}; -export { RNRenderer }; diff --git a/packages/react-native-reanimated/src/platform-specific/findHostInstance.ts b/packages/react-native-reanimated/src/platform-specific/findHostInstance.ts new file mode 100644 index 00000000000..00d56154e40 --- /dev/null +++ b/packages/react-native-reanimated/src/platform-specific/findHostInstance.ts @@ -0,0 +1,77 @@ +/* eslint-disable camelcase */ +'use strict'; + +import type { IAnimatedComponentInternal } from '../createAnimatedComponent/commonTypes'; +import { ReanimatedError } from '../errors'; +import { isFabric } from '../PlatformChecker'; + +type HostInstanceFabric = { + __internalInstanceHandle?: Record; + __nativeTag?: number; + _viewConfig?: Record; +}; + +type HostInstancePaper = { + _nativeTag?: number; + viewConfig?: Record; +}; + +export type HostInstance = HostInstanceFabric & HostInstancePaper; + +function findHostInstanceFastPath(maybeNativeRef: HostInstance) { + if ( + maybeNativeRef.__internalInstanceHandle && + maybeNativeRef.__nativeTag && + maybeNativeRef._viewConfig + ) { + // This is a native ref to a Fabric component + return maybeNativeRef; + } + if (maybeNativeRef._nativeTag && maybeNativeRef.viewConfig) { + // This is a native ref to a Paper component + return maybeNativeRef; + } + // That means it’s a ref to a non-native component, and it’s necessary + // to call `findHostInstance_DEPRECATED` on them. + return undefined; +} + +function resolveFindHostInstance_DEPRECATED() { + if (findHostInstance_DEPRECATED !== undefined) { + return; + } + if (isFabric()) { + try { + findHostInstance_DEPRECATED = + require('react-native/Libraries/Renderer/shims/ReactFabric').findHostInstance_DEPRECATED; + } catch (e) { + throw new ReanimatedError( + 'Failed to resolve findHostInstance_DEPRECATED' + ); + } + } else { + findHostInstance_DEPRECATED = + require('react-native/Libraries/Renderer/shims/ReactNative').findHostInstance_DEPRECATED; + } +} + +let findHostInstance_DEPRECATED: (ref: unknown) => HostInstance; +export function findHostInstance( + component: IAnimatedComponentInternal | React.Component +): HostInstance { + // Fast path for native refs + const hostInstance = findHostInstanceFastPath( + (component as IAnimatedComponentInternal)._componentRef as HostInstance + ); + if (hostInstance !== undefined) { + return hostInstance; + } + + resolveFindHostInstance_DEPRECATED(); + // Fabric implementation of findHostInstance_DEPRECATED doesn't accept a ref as an argument + return findHostInstance_DEPRECATED( + isFabric() + ? component + : (component as IAnimatedComponentInternal)._componentRef + ); +} diff --git a/packages/react-native-reanimated/src/platform-specific/findHostInstance.web.ts b/packages/react-native-reanimated/src/platform-specific/findHostInstance.web.ts new file mode 100644 index 00000000000..ca342dfd2d4 --- /dev/null +++ b/packages/react-native-reanimated/src/platform-specific/findHostInstance.web.ts @@ -0,0 +1,3 @@ +'use strict'; + +export function findHostInstance(_component: any): void {}