Skip to content

Commit 3554c88

Browse files
authored
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: react-native-community/discussions-and-proposals#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
1 parent c57b90f commit 3554c88

7 files changed

+43
-33
lines changed

packages/react-native-renderer/src/ReactFabric.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import {
4040
sendAccessibilityEvent,
4141
getNodeFromInternalInstanceHandle,
4242
} from './ReactNativePublicCompat';
43+
import {getPublicInstanceFromInternalInstanceHandle} from './ReactFabricHostConfig';
4344

4445
// $FlowFixMe[missing-local-annot]
4546
function onRecoverableError(error) {
@@ -124,6 +125,10 @@ export {
124125
// This method allows it to acess the most recent shadow node for
125126
// the instance (it's only accessible through it).
126127
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,
127132
};
128133

129134
injectIntoDevTools({

packages/react-native-renderer/src/ReactFabricHostConfig.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,13 @@ export function getPublicInstance(instance: Instance): null | PublicInstance {
241241
return null;
242242
}
243243

244+
export function getPublicInstanceFromInternalInstanceHandle(
245+
internalInstanceHandle: Object,
246+
): null | PublicInstance {
247+
const instance: Instance = internalInstanceHandle.stateNode;
248+
return getPublicInstance(instance);
249+
}
250+
244251
export function prepareForCommit(containerInfo: Container): null | Object {
245252
// Noop
246253
return null;

packages/react-native-renderer/src/ReactFabricPublicInstanceUtils.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
*/
99

1010
import type {ReactFabricHostComponent} from './ReactFabricPublicInstance';
11+
import {getNodeFromInternalInstanceHandle} from './ReactNativePublicCompat';
1112

1213
/**
1314
* IMPORTANT: This module is used in Paper and Fabric. It needs to be defined
@@ -22,8 +23,14 @@ export function getNativeTagFromPublicInstance(
2223
return publicInstance.__nativeTag;
2324
}
2425

25-
export function getInternalInstanceHandleFromPublicInstance(
26+
export function getNodeFromPublicInstance(
2627
publicInstance: ReactFabricHostComponent,
2728
): mixed {
28-
return publicInstance.__internalInstanceHandle;
29+
if (publicInstance.__internalInstanceHandle == null) {
30+
return null;
31+
}
32+
33+
return getNodeFromInternalInstanceHandle(
34+
publicInstance.__internalInstanceHandle,
35+
);
2936
}

packages/react-native-renderer/src/ReactNativeFiberInspector.js

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import {HostComponent} from 'react-reconciler/src/ReactWorkTags';
2020
import {UIManager} from 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface';
2121
import {enableGetInspectorDataForInstanceInProduction} from 'shared/ReactFeatureFlags';
2222
import {getClosestInstanceFromNode} from './ReactNativeComponentTree';
23-
import {getInternalInstanceHandleFromPublicInstance} from './ReactFabricPublicInstanceUtils';
23+
import {getNodeFromPublicInstance} from './ReactFabricPublicInstanceUtils';
2424
import {getNodeFromInternalInstanceHandle} from './ReactNativePublicCompat';
2525

2626
const emptyObject = {};
@@ -196,12 +196,7 @@ function getInspectorDataForViewAtPoint(
196196
if (__DEV__) {
197197
let closestInstance = null;
198198

199-
const fabricInstanceHandle =
200-
getInternalInstanceHandleFromPublicInstance(inspectedView);
201-
const fabricNode =
202-
fabricInstanceHandle != null
203-
? getNodeFromInternalInstanceHandle(fabricInstanceHandle)
204-
: null;
199+
const fabricNode = getNodeFromPublicInstance(inspectedView);
205200
if (fabricNode) {
206201
// For Fabric we can look up the instance handle directly and measure it.
207202
nativeFabricUIManager.findNodeAtPoint(

packages/react-native-renderer/src/ReactNativePublicCompat.js

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import ReactSharedInternals from 'shared/ReactSharedInternals';
2424
import getComponentNameFromType from 'shared/getComponentNameFromType';
2525

2626
import {
27-
getInternalInstanceHandleFromPublicInstance,
27+
getNodeFromPublicInstance,
2828
getNativeTagFromPublicInstance,
2929
} from './ReactFabricPublicInstanceUtils';
3030

@@ -176,14 +176,10 @@ export function dispatchCommand(
176176
return;
177177
}
178178

179-
const internalInstanceHandle =
180-
getInternalInstanceHandleFromPublicInstance(handle);
179+
const node = getNodeFromPublicInstance(handle);
181180

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);
187183
} else {
188184
UIManager.dispatchViewManagerCommand(nativeTag, command, args);
189185
}
@@ -204,13 +200,9 @@ export function sendAccessibilityEvent(handle: any, eventType: string) {
204200
return;
205201
}
206202

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);
214206
} else {
215207
legacySendAccessibilityEvent(nativeTag, eventType);
216208
}

packages/react-native-renderer/src/ReactNativeTypes.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,8 @@ export type ReactNativeType = {
213213
};
214214

215215
export opaque type Node = mixed;
216+
type InternalInstanceHandle = mixed;
217+
type PublicInstance = mixed;
216218

217219
export type ReactFabricType = {
218220
findHostInstance_DEPRECATED<TElementType: ElementType>(
@@ -237,7 +239,12 @@ export type ReactFabricType = {
237239
concurrentRoot: ?boolean,
238240
): ?ElementRef<ElementType>,
239241
unmountComponentAtNode(containerTag: number): void,
240-
getNodeFromInternalInstanceHandle(internalInstanceHandle: mixed): ?Node,
242+
getNodeFromInternalInstanceHandle(
243+
internalInstanceHandle: InternalInstanceHandle,
244+
): ?Node,
245+
getPublicInstanceFromInternalInstanceHandle(
246+
internalInstanceHandle: InternalInstanceHandle,
247+
): PublicInstance,
241248
...
242249
};
243250

packages/react-native-renderer/src/__tests__/ReactFabric-test.internal.js

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ let createReactNativeComponentClass;
1616
let StrictMode;
1717
let act;
1818
let getNativeTagFromPublicInstance;
19-
let getInternalInstanceHandleFromPublicInstance;
19+
let getNodeFromPublicInstance;
2020

2121
const DISPATCH_COMMAND_REQUIRES_HOST_COMPONENT =
2222
"Warning: dispatchCommand was called with a ref that isn't a " +
@@ -44,8 +44,8 @@ describe('ReactFabric', () => {
4444
.ReactNativeViewConfigRegistry.register;
4545
getNativeTagFromPublicInstance =
4646
require('../ReactFabricPublicInstanceUtils').getNativeTagFromPublicInstance;
47-
getInternalInstanceHandleFromPublicInstance =
48-
require('../ReactFabricPublicInstanceUtils').getInternalInstanceHandleFromPublicInstance;
47+
getNodeFromPublicInstance =
48+
require('../ReactFabricPublicInstanceUtils').getNodeFromPublicInstance;
4949

5050
act = require('internal-test-utils').act;
5151
});
@@ -1032,10 +1032,7 @@ describe('ReactFabric', () => {
10321032
nativeFabricUIManager.createNode.mock.results[0].value;
10331033
expect(expectedShadowNode).toEqual(expect.any(Object));
10341034

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);
10401037
});
10411038
});

0 commit comments

Comments
 (0)