diff --git a/src/reanimated2/commonTypes.ts b/src/reanimated2/commonTypes.ts index e4e546b989e..abffb927279 100644 --- a/src/reanimated2/commonTypes.ts +++ b/src/reanimated2/commonTypes.ts @@ -55,6 +55,12 @@ export type ShareableRef = { __hostObjectShareableJSRef: T; }; +// In case of objects with depth or arrays of objects or arrays of arrays etc. +// we add this utility type that makes it a SharaebleRef of the outermost type. +export type FlatShareableRef = T extends ShareableRef + ? ShareableRef + : ShareableRef; + export type ShareableSyncDataHolderRef = { __hostObjectShareableJSRefSyncDataHolder: T; }; diff --git a/src/reanimated2/globals.d.ts b/src/reanimated2/globals.d.ts index e90d42fd165..520d0171115 100644 --- a/src/reanimated2/globals.d.ts +++ b/src/reanimated2/globals.d.ts @@ -8,6 +8,7 @@ import type { ShareableSyncDataHolderRef, ShadowNodeWrapper, ComplexWorkletFunction, + FlatShareableRef, } from './commonTypes'; import type { AnimatedStyle } from './helperTypes'; import type { FrameCallbackRegistryUI } from './frameCallback/FrameCallbackRegistryUI'; @@ -36,7 +37,7 @@ declare global { ) => void; var _notifyAboutEnd: (tag: number, removeView: boolean) => void; var _setGestureState: (handlerTag: number, newState: number) => void; - var _makeShareableClone: (value: T) => ShareableRef; + var _makeShareableClone: (value: T) => FlatShareableRef; var _updateDataSynchronously: ( dataHolder: ShareableSyncDataHolderRef, data: ShareableRef diff --git a/src/reanimated2/shareables.ts b/src/reanimated2/shareables.ts index 03575ab9e4f..b85b1e17580 100644 --- a/src/reanimated2/shareables.ts +++ b/src/reanimated2/shareables.ts @@ -1,5 +1,9 @@ import NativeReanimatedModule from './NativeReanimated'; -import type { ShareableRef, WorkletFunction } from './commonTypes'; +import type { + FlatShareableRef, + ShareableRef, + WorkletFunction, +} from './commonTypes'; import { shouldBeUseWeb } from './PlatformChecker'; import { registerWorkletStackDetails } from './errors'; import { jsVersion } from './platform-specific/jsVersion'; @@ -20,7 +24,8 @@ const _shareableFlag = Symbol('shareable flag'); const MAGIC_KEY = 'REANIMATED_MAGIC_KEY'; -function isHostObject(value: NonNullable): boolean { +function isHostObject(value: NonNullable) { + 'worklet'; // We could use JSI to determine whether an object is a host object, however // the below workaround works well and is way faster than an additional JSI call. // We use the fact that host objects have broken implementation of `hasOwnProperty` @@ -247,28 +252,45 @@ function getWorkletCode(value: WorkletFunction) { return code; } -export function makeShareableCloneOnUIRecursive(value: T): ShareableRef { +type RemoteFunction = { + __remoteFunction: FlatShareableRef; +}; + +function isRemoteFunction(value: object): value is RemoteFunction { + 'worklet'; + return '__remoteFunction' in value; +} + +export function makeShareableCloneOnUIRecursive( + value: T +): FlatShareableRef { 'worklet'; if (USE_STUB_IMPLEMENTATION) { // @ts-ignore web is an interesting place where we don't run a secondary VM on the UI thread // see more details in the comment where USE_STUB_IMPLEMENTATION is defined. return value; } - function cloneRecursive(value: T): ShareableRef { - const type = typeof value; - if ((type === 'object' || type === 'function') && value !== null) { - let toAdapt: any; + function cloneRecursive(value: T): FlatShareableRef { + if ( + (typeof value === 'object' && value !== null) || + typeof value === 'function' + ) { + if (isHostObject(value)) { + return value as FlatShareableRef; + } + if (isRemoteFunction(value)) { + return value.__remoteFunction; + } if (Array.isArray(value)) { - toAdapt = value.map((element) => cloneRecursive(element)); - } else if (value !== undefined) { - toAdapt = {}; - for (const [key, element] of Object.entries( - value as Record - )) { - toAdapt[key] = cloneRecursive(element); - } + return _makeShareableClone( + value.map(cloneRecursive) + ) as FlatShareableRef; + } + const toAdapt: Record> = {}; + for (const [key, element] of Object.entries(value)) { + toAdapt[key] = cloneRecursive(element); } - return _makeShareableClone(toAdapt); + return _makeShareableClone(toAdapt) as FlatShareableRef; } return _makeShareableClone(value); }