@samitouri / QOS-React-2 / commits / 3554c8852f

Clean interface for public instances between React and React Native (#26416)

## Summary We are going to move the definition of public instances from React to React Native to have them together with the native methods in Fabric that they invoke. This will allow us to have a better type safety between them and iterate faster on the implementation of this proposal: https://github.com/react-native-community/discussions-and-proposals/pull/607 The interface between React and React Native would look like this after this change and a following PR (#26418): React → React Native: ```javascript ReactNativePrivateInterface.createPublicInstance // to provide via refs ReactNativePrivateInterface.getNodeFromPublicInstance // for DevTools, commands, etc. ReactNativePrivateInterface.getNativeTagFromPublicInstance // to implement `findNodeHandle` ``` React Native → React (ReactFabric): ```javascript ReactFabric.getNodeFromInternalInstanceHandle // to get most recent node to call into native ReactFabric.getPublicInstanceFromInternalInstanceHandle // to get public instances from results from native ``` ## How did you test this change? Flow Existing unit tests

Rubén Norte committed Mar 20, 2023 at 13:35 UTC 3554c8852fe209ad02380ebd24d32f56d6399906
7 files changed +43 -33
packages/react-native-renderer/src/ReactFabric.js
+5
@@ -40,6 +40,7 @@ import {
40 sendAccessibilityEvent,
41 getNodeFromInternalInstanceHandle,
42 } from './ReactNativePublicCompat';
43 +import {getPublicInstanceFromInternalInstanceHandle} from './ReactFabricHostConfig';
44
45 // $FlowFixMe[missing-local-annot]
46 function onRecoverableError(error) {
@@ -124,6 +125,10 @@ export {
125 // This method allows it to acess the most recent shadow node for
126 // the instance (it's only accessible through it).
127 getNodeFromInternalInstanceHandle,
128 + // Fabric native methods to traverse the host tree return the same internal
129 + // instance handles we use to dispatch events. This provides a way to access
130 + // the public instances we created from them (potentially created lazily).
131 + getPublicInstanceFromInternalInstanceHandle,
132 };
133
134 injectIntoDevTools({
packages/react-native-renderer/src/ReactFabricHostConfig.js
+7
@@ -241,6 +241,13 @@ export function getPublicInstance(instance: Instance): null | PublicInstance {
241 return null;
242 }
243
244 +export function getPublicInstanceFromInternalInstanceHandle(
245 + internalInstanceHandle: Object,
246 +): null | PublicInstance {
247 + const instance: Instance = internalInstanceHandle.stateNode;
248 + return getPublicInstance(instance);
249 +}
250 +
251 export function prepareForCommit(containerInfo: Container): null | Object {
252 // Noop
253 return null;
packages/react-native-renderer/src/ReactFabricPublicInstanceUtils.js
+9 -2
@@ -8,6 +8,7 @@
8 */
9
10 import type {ReactFabricHostComponent} from './ReactFabricPublicInstance';
11 +import {getNodeFromInternalInstanceHandle} from './ReactNativePublicCompat';
12
13 /**
14 * IMPORTANT: This module is used in Paper and Fabric. It needs to be defined
@@ -22,8 +23,14 @@ export function getNativeTagFromPublicInstance(
23 return publicInstance.__nativeTag;
24 }
25
25 -export function getInternalInstanceHandleFromPublicInstance(
26 +export function getNodeFromPublicInstance(
27 publicInstance: ReactFabricHostComponent,
28 ): mixed {
28 - return publicInstance.__internalInstanceHandle;
29 + if (publicInstance.__internalInstanceHandle == null) {
30 + return null;
31 + }
32 +
33 + return getNodeFromInternalInstanceHandle(
34 + publicInstance.__internalInstanceHandle,
35 + );
36 }
packages/react-native-renderer/src/ReactNativeFiberInspector.js
+2 -7
@@ -20,7 +20,7 @@ import {HostComponent} from 'react-reconciler/src/ReactWorkTags';
20 import {UIManager} from 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface';
21 import {enableGetInspectorDataForInstanceInProduction} from 'shared/ReactFeatureFlags';
22 import {getClosestInstanceFromNode} from './ReactNativeComponentTree';
23 -import {getInternalInstanceHandleFromPublicInstance} from './ReactFabricPublicInstanceUtils';
23 +import {getNodeFromPublicInstance} from './ReactFabricPublicInstanceUtils';
24 import {getNodeFromInternalInstanceHandle} from './ReactNativePublicCompat';
25
26 const emptyObject = {};
@@ -196,12 +196,7 @@ function getInspectorDataForViewAtPoint(
196 if (__DEV__) {
197 let closestInstance = null;
198
199 - const fabricInstanceHandle =
200 - getInternalInstanceHandleFromPublicInstance(inspectedView);
201 - const fabricNode =
202 - fabricInstanceHandle != null
203 - ? getNodeFromInternalInstanceHandle(fabricInstanceHandle)
204 - : null;
199 + const fabricNode = getNodeFromPublicInstance(inspectedView);
200 if (fabricNode) {
201 // For Fabric we can look up the instance handle directly and measure it.
202 nativeFabricUIManager.findNodeAtPoint(
packages/react-native-renderer/src/ReactNativePublicCompat.js
+7 -15
@@ -24,7 +24,7 @@ import ReactSharedInternals from 'shared/ReactSharedInternals';
24 import getComponentNameFromType from 'shared/getComponentNameFromType';
25
26 import {
27 - getInternalInstanceHandleFromPublicInstance,
27 + getNodeFromPublicInstance,
28 getNativeTagFromPublicInstance,
29 } from './ReactFabricPublicInstanceUtils';
30
@@ -176,14 +176,10 @@ export function dispatchCommand(
176 return;
177 }
178
179 - const internalInstanceHandle =
180 - getInternalInstanceHandleFromPublicInstance(handle);
179 + const node = getNodeFromPublicInstance(handle);
180
182 - if (internalInstanceHandle != null) {
183 - const node = getNodeFromInternalInstanceHandle(internalInstanceHandle);
184 - if (node != null) {
185 - nativeFabricUIManager.dispatchCommand(node, command, args);
186 - }
181 + if (node != null) {
182 + nativeFabricUIManager.dispatchCommand(node, command, args);
183 } else {
184 UIManager.dispatchViewManagerCommand(nativeTag, command, args);
185 }
@@ -204,13 +200,9 @@ export function sendAccessibilityEvent(handle: any, eventType: string) {
200 return;
201 }
202
207 - const internalInstanceHandle =
208 - getInternalInstanceHandleFromPublicInstance(handle);
209 - if (internalInstanceHandle != null) {
210 - const node = getNodeFromInternalInstanceHandle(internalInstanceHandle);
211 - if (node != null) {
212 - nativeFabricUIManager.sendAccessibilityEvent(node, eventType);
213 - }
203 + const node = getNodeFromPublicInstance(handle);
204 + if (node != null) {
205 + nativeFabricUIManager.sendAccessibilityEvent(node, eventType);
206 } else {
207 legacySendAccessibilityEvent(nativeTag, eventType);
208 }
packages/react-native-renderer/src/ReactNativeTypes.js
+8 -1
@@ -213,6 +213,8 @@ export type ReactNativeType = {
213 };
214
215 export opaque type Node = mixed;
216 +type InternalInstanceHandle = mixed;
217 +type PublicInstance = mixed;
218
219 export type ReactFabricType = {
220 findHostInstance_DEPRECATED<TElementType: ElementType>(
@@ -237,7 +239,12 @@ export type ReactFabricType = {
239 concurrentRoot: ?boolean,
240 ): ?ElementRef<ElementType>,
241 unmountComponentAtNode(containerTag: number): void,
240 - getNodeFromInternalInstanceHandle(internalInstanceHandle: mixed): ?Node,
242 + getNodeFromInternalInstanceHandle(
243 + internalInstanceHandle: InternalInstanceHandle,
244 + ): ?Node,
245 + getPublicInstanceFromInternalInstanceHandle(
246 + internalInstanceHandle: InternalInstanceHandle,
247 + ): PublicInstance,
248 ...
249 };
250
packages/react-native-renderer/src/__tests__/ReactFabric-test.internal.js
+5 -8
@@ -16,7 +16,7 @@ let createReactNativeComponentClass;
16 let StrictMode;
17 let act;
18 let getNativeTagFromPublicInstance;
19 -let getInternalInstanceHandleFromPublicInstance;
19 +let getNodeFromPublicInstance;
20
21 const DISPATCH_COMMAND_REQUIRES_HOST_COMPONENT =
22 "Warning: dispatchCommand was called with a ref that isn't a " +
@@ -44,8 +44,8 @@ describe('ReactFabric', () => {
44 .ReactNativeViewConfigRegistry.register;
45 getNativeTagFromPublicInstance =
46 require('../ReactFabricPublicInstanceUtils').getNativeTagFromPublicInstance;
47 - getInternalInstanceHandleFromPublicInstance =
48 - require('../ReactFabricPublicInstanceUtils').getInternalInstanceHandleFromPublicInstance;
47 + getNodeFromPublicInstance =
48 + require('../ReactFabricPublicInstanceUtils').getNodeFromPublicInstance;
49
50 act = require('internal-test-utils').act;
51 });
@@ -1032,10 +1032,7 @@ describe('ReactFabric', () => {
1032 nativeFabricUIManager.createNode.mock.results[0].value;
1033 expect(expectedShadowNode).toEqual(expect.any(Object));
1034
1035 - const internalInstanceHandle =
1036 - getInternalInstanceHandleFromPublicInstance(viewRef);
1037 - expect(
1038 - ReactFabric.getNodeFromInternalInstanceHandle(internalInstanceHandle),
1039 - ).toBe(expectedShadowNode);
1035 + const node = getNodeFromPublicInstance(viewRef);
1036 + expect(node).toBe(expectedShadowNode);
1037 });
1038 });