From 02ea4177a02ad88be0713ed56c1fc4995e2966e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20Norte?= Date: Fri, 10 Mar 2023 08:02:46 -0800 Subject: [PATCH] Prepare for next React Native sync with new instance format (#36438) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/36438 This makes the `react-native` repository compatible with the next sync from react after the changes in https://github.com/facebook/react/pull/26321 land. That PR is changing the format of the Fabric instance and we have a few instances where we assume the internal structure of that instance in the repository. Changelog: [internal] Differential Revision: D43980374 fbshipit-source-id: d2e5c03dc595bd181fbdfb1bed28155dd3840e40 --- Libraries/Animated/useAnimatedProps.js | 15 ++++------ .../ScrollView/ScrollViewStickyHeader.js | 6 ++-- .../TraceUpdateOverlay/TraceUpdateOverlay.js | 8 ++++- Libraries/Inspector/DevtoolsOverlay.js | 8 +++-- .../public/ReactFabricPublicInstance.js | 30 +++++++++++++++++++ 5 files changed, 51 insertions(+), 16 deletions(-) create mode 100644 Libraries/Renderer/public/ReactFabricPublicInstance.js diff --git a/Libraries/Animated/useAnimatedProps.js b/Libraries/Animated/useAnimatedProps.js index 1b7d81009fd885..27ca26ced09233 100644 --- a/Libraries/Animated/useAnimatedProps.js +++ b/Libraries/Animated/useAnimatedProps.js @@ -10,6 +10,7 @@ 'use strict'; +import {isPublicInstance as isFabricPublicInstance} from '../Renderer/public/ReactFabricPublicInstance'; import useRefEffect from '../Utilities/useRefEffect'; import {AnimatedEvent} from './AnimatedEvent'; import NativeAnimatedHelper from './NativeAnimatedHelper'; @@ -183,7 +184,7 @@ function getEventTarget(instance: TInstance): TInstance { // $FlowFixMe[unclear-type] - Legacy instance assumptions. function isFabricInstance(instance: any): boolean { return ( - hasFabricHandle(instance) || + isFabricPublicInstance(instance) || // Some components have a setNativeProps function but aren't a host component // such as lists like FlatList and SectionList. These should also use // forceUpdate in Fabric since setNativeProps doesn't exist on the underlying @@ -192,13 +193,9 @@ function isFabricInstance(instance: any): boolean { // If these components end up using forwardRef then these hacks can go away // as instance would actually be the underlying host component and the above check // would be sufficient. - hasFabricHandle(instance?.getNativeScrollRef?.()) || - hasFabricHandle(instance?.getScrollResponder?.()?.getNativeScrollRef?.()) + isFabricPublicInstance(instance?.getNativeScrollRef?.()) || + isFabricPublicInstance( + instance?.getScrollResponder?.()?.getNativeScrollRef?.(), + ) ); } - -// $FlowFixMe[unclear-type] - Legacy instance assumptions. -function hasFabricHandle(instance: any): boolean { - // eslint-disable-next-line dot-notation - return instance?.['_internalInstanceHandle']?.stateNode?.canonical != null; -} diff --git a/Libraries/Components/ScrollView/ScrollViewStickyHeader.js b/Libraries/Components/ScrollView/ScrollViewStickyHeader.js index 9d59cf527f1ddd..1450d664988aa2 100644 --- a/Libraries/Components/ScrollView/ScrollViewStickyHeader.js +++ b/Libraries/Components/ScrollView/ScrollViewStickyHeader.js @@ -11,6 +11,7 @@ import type {LayoutEvent} from '../../Types/CoreEventTypes'; import Animated from '../../Animated/Animated'; +import {isPublicInstance as isFabricPublicInstance} from '../../Renderer/public/ReactFabricPublicInstance'; import StyleSheet from '../../StyleSheet/StyleSheet'; import Platform from '../../Utilities/Platform'; import useMergeRefs from '../../Utilities/useMergeRefs'; @@ -64,10 +65,7 @@ const ScrollViewStickyHeaderWithForwardedRef: React.AbstractComponent< ref.setNextHeaderY = value => { setNextHeaderLayoutY(value); }; - // Avoid dot notation because at Meta, private properties are obfuscated. - // $FlowFixMe[prop-missing] - const _internalInstanceHandler = ref['_internalInstanceHandle']; // eslint-disable-line dot-notation - setIsFabric(Boolean(_internalInstanceHandler?.stateNode?.canonical)); + setIsFabric(isFabricPublicInstance(ref)); }; const ref: (React.ElementRef | null) => void = // $FlowFixMe[incompatible-type] - Ref is mutated by `callbackRef`. diff --git a/Libraries/Components/TraceUpdateOverlay/TraceUpdateOverlay.js b/Libraries/Components/TraceUpdateOverlay/TraceUpdateOverlay.js index 6d585d1a1ae87a..cee4d0efdb98bd 100644 --- a/Libraries/Components/TraceUpdateOverlay/TraceUpdateOverlay.js +++ b/Libraries/Components/TraceUpdateOverlay/TraceUpdateOverlay.js @@ -34,6 +34,8 @@ interface Agent { } type TraceNode = { + publicInstance?: TraceNode, + // TODO: remove this field when syncing the new version of the renderer from React to React Native. canonical?: TraceNode, measure?: ( ( @@ -100,7 +102,11 @@ export default function TraceUpdateOverlay(): React.Node { const newFramesToDraw: Array> = []; nodesToDraw.forEach(({node, color}) => { - const component = node.canonical ?? node; + // `publicInstance` => Fabric + // TODO: remove this check when syncing the new version of the renderer from React to React Native. + // `canonical` => Legacy Fabric + // `node` => Legacy renderer + const component = node.publicInstance ?? node.canonical ?? node; if (!component || !component.measure) { return; } diff --git a/Libraries/Inspector/DevtoolsOverlay.js b/Libraries/Inspector/DevtoolsOverlay.js index afeef46605b4ec..cdb874ef610909 100644 --- a/Libraries/Inspector/DevtoolsOverlay.js +++ b/Libraries/Inspector/DevtoolsOverlay.js @@ -51,8 +51,12 @@ export default function DevtoolsOverlay({ function onAgentShowNativeHighlight(node: any) { clearTimeout(hideTimeoutId); - // Shape of `node` is different in Fabric. - const component = node.canonical ?? node; + + // `publicInstance` => Fabric + // TODO: remove this check when syncing the new version of the renderer from React to React Native. + // `canonical` => Legacy Fabric + // `node` => Legacy renderer + const component = node.publicInstance ?? node.canonical ?? node; if (!component || !component.measure) { return; } diff --git a/Libraries/Renderer/public/ReactFabricPublicInstance.js b/Libraries/Renderer/public/ReactFabricPublicInstance.js new file mode 100644 index 00000000000000..5cfdc14313a0e2 --- /dev/null +++ b/Libraries/Renderer/public/ReactFabricPublicInstance.js @@ -0,0 +1,30 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + * @flow strict + */ + +export function isPublicInstance(maybeInstance: mixed): boolean { + return ( + maybeInstance != null && + // TODO: implement a better check (maybe using instanceof) when the instance is defined in the React Native repository. + (maybeInstance.__nativeTag != null || + // TODO: remove this check when syncing the new version of the renderer from React to React Native. + isLegacyFabricInstance(maybeInstance)) + ); +} + +function isLegacyFabricInstance(maybeInstance: mixed): boolean { + /* eslint-disable dot-notation */ + return ( + maybeInstance != null && + // $FlowExpectedError[incompatible-use] + maybeInstance['_internalInstanceHandle'] != null && + maybeInstance['_internalInstanceHandle'].stateNode != null && + maybeInstance['_internalInstanceHandle'].stateNode.canonical != null + ); +}