Skip to content

Commit 90087f0

Browse files
committed
Extracted definition and access to public instances to a separate module in Fabric (v2)
1 parent e8bdba3 commit 90087f0

13 files changed

+392
-206
lines changed

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import {
3838
findNodeHandle,
3939
dispatchCommand,
4040
sendAccessibilityEvent,
41+
getNodeFromInternalInstanceHandle,
4142
} from './ReactNativePublicCompat';
4243

4344
// $FlowFixMe[missing-local-annot]
@@ -119,6 +120,10 @@ export {
119120
// This export is typically undefined in production builds.
120121
// See the "enableGetInspectorDataForInstanceInProduction" flag.
121122
getInspectorDataForInstance,
123+
// The public instance has a reference to the internal instance handle.
124+
// This method allows it to acess the most recent shadow node for
125+
// the instance (it's only accessible through it).
126+
getNodeFromInternalInstanceHandle,
122127
};
123128

124129
injectIntoDevTools({

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,15 @@ import {getPublicInstance} from './ReactFabricHostConfig';
2020
// This is ok in DOM because they types are interchangeable, but in React Native
2121
// they aren't.
2222
function getInstanceFromNode(node: Instance | TextInstance): Fiber | null {
23+
const instance: Instance = (node: $FlowFixMe); // In React Native, node is never a text instance
24+
25+
if (
26+
instance.canonical != null &&
27+
instance.canonical.internalInstanceHandle != null
28+
) {
29+
return instance.canonical.internalInstanceHandle;
30+
}
31+
2332
// $FlowFixMe[incompatible-return] DevTools incorrectly passes a fiber in React Native.
2433
return node;
2534
}

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

Lines changed: 29 additions & 159 deletions
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,13 @@
77
* @flow
88
*/
99

10-
import type {ElementRef} from 'react';
11-
import type {
12-
HostComponent,
13-
MeasureInWindowOnSuccessCallback,
14-
MeasureLayoutOnSuccessCallback,
15-
MeasureOnSuccessCallback,
16-
INativeMethods,
17-
ViewConfig,
18-
TouchedViewDataAtPoint,
19-
} from './ReactNativeTypes';
20-
21-
import {warnForStyleProps} from './NativeMethodsMixinUtils';
10+
import type {TouchedViewDataAtPoint, ViewConfig} from './ReactNativeTypes';
11+
import {
12+
createPublicInstance,
13+
type ReactFabricHostComponent,
14+
} from './ReactFabricPublicInstance';
2215
import {create, diff} from './ReactNativeAttributePayload';
23-
2416
import {dispatchEvent} from './ReactFabricEventEmitter';
25-
2617
import {
2718
DefaultEventPriority,
2819
DiscreteEventPriority,
@@ -31,7 +22,6 @@ import {
3122
// Modules provided by RN:
3223
import {
3324
ReactNativeViewConfigRegistry,
34-
TextInputState,
3525
deepFreezeAndThrowOnMutationInDev,
3626
} from 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface';
3727

@@ -46,14 +36,9 @@ const {
4636
appendChildToSet: appendChildNodeToSet,
4737
completeRoot,
4838
registerEventHandler,
49-
measure: fabricMeasure,
50-
measureInWindow: fabricMeasureInWindow,
51-
measureLayout: fabricMeasureLayout,
5239
unstable_DefaultEventPriority: FabricDefaultPriority,
5340
unstable_DiscreteEventPriority: FabricDiscretePriority,
5441
unstable_getCurrentEventPriority: fabricGetCurrentEventPriority,
55-
setNativeProps,
56-
getBoundingClientRect: fabricGetBoundingClientRect,
5742
} = nativeFabricUIManager;
5843

5944
const {get: getViewConfigForType} = ReactNativeViewConfigRegistry;
@@ -68,9 +53,17 @@ type Node = Object;
6853
export type Type = string;
6954
export type Props = Object;
7055
export type Instance = {
56+
// Reference to the shadow node.
7157
node: Node,
72-
canonical: ReactFabricHostComponent,
73-
...
58+
canonical: {
59+
nativeTag: number,
60+
viewConfig: ViewConfig,
61+
currentProps: Props,
62+
// Reference to the React handle (the fiber)
63+
internalInstanceHandle: Object,
64+
// Exposed through refs.
65+
publicInstance: ReactFabricHostComponent,
66+
},
7467
};
7568
export type TextInstance = {node: Node, ...};
7669
export type HydratableInstance = Instance | TextInstance;
@@ -104,137 +97,6 @@ if (registerEventHandler) {
10497
registerEventHandler(dispatchEvent);
10598
}
10699

107-
const noop = () => {};
108-
109-
/**
110-
* This is used for refs on host components.
111-
*/
112-
class ReactFabricHostComponent implements INativeMethods {
113-
_nativeTag: number;
114-
viewConfig: ViewConfig;
115-
currentProps: Props;
116-
_internalInstanceHandle: Object;
117-
118-
constructor(
119-
tag: number,
120-
viewConfig: ViewConfig,
121-
props: Props,
122-
internalInstanceHandle: Object,
123-
) {
124-
this._nativeTag = tag;
125-
this.viewConfig = viewConfig;
126-
this.currentProps = props;
127-
this._internalInstanceHandle = internalInstanceHandle;
128-
}
129-
130-
blur() {
131-
TextInputState.blurTextInput(this);
132-
}
133-
134-
focus() {
135-
TextInputState.focusTextInput(this);
136-
}
137-
138-
measure(callback: MeasureOnSuccessCallback) {
139-
const node = getShadowNodeFromInternalInstanceHandle(
140-
this._internalInstanceHandle,
141-
);
142-
if (node != null) {
143-
fabricMeasure(node, callback);
144-
}
145-
}
146-
147-
measureInWindow(callback: MeasureInWindowOnSuccessCallback) {
148-
const node = getShadowNodeFromInternalInstanceHandle(
149-
this._internalInstanceHandle,
150-
);
151-
if (node != null) {
152-
fabricMeasureInWindow(node, callback);
153-
}
154-
}
155-
156-
measureLayout(
157-
relativeToNativeNode: number | ElementRef<HostComponent<mixed>>,
158-
onSuccess: MeasureLayoutOnSuccessCallback,
159-
onFail?: () => void /* currently unused */,
160-
) {
161-
if (
162-
typeof relativeToNativeNode === 'number' ||
163-
!(relativeToNativeNode instanceof ReactFabricHostComponent)
164-
) {
165-
if (__DEV__) {
166-
console.error(
167-
'Warning: ref.measureLayout must be called with a ref to a native component.',
168-
);
169-
}
170-
171-
return;
172-
}
173-
174-
const toStateNode = getShadowNodeFromInternalInstanceHandle(
175-
this._internalInstanceHandle,
176-
);
177-
const fromStateNode = getShadowNodeFromInternalInstanceHandle(
178-
relativeToNativeNode._internalInstanceHandle,
179-
);
180-
181-
if (toStateNode != null && fromStateNode != null) {
182-
fabricMeasureLayout(
183-
toStateNode,
184-
fromStateNode,
185-
onFail != null ? onFail : noop,
186-
onSuccess != null ? onSuccess : noop,
187-
);
188-
}
189-
}
190-
191-
unstable_getBoundingClientRect(): DOMRect {
192-
const node = getShadowNodeFromInternalInstanceHandle(
193-
this._internalInstanceHandle,
194-
);
195-
if (node != null) {
196-
const rect = fabricGetBoundingClientRect(node);
197-
198-
if (rect) {
199-
return new DOMRect(rect[0], rect[1], rect[2], rect[3]);
200-
}
201-
}
202-
203-
// Empty rect if any of the above failed
204-
return new DOMRect(0, 0, 0, 0);
205-
}
206-
207-
setNativeProps(nativeProps: Object) {
208-
if (__DEV__) {
209-
warnForStyleProps(nativeProps, this.viewConfig.validAttributes);
210-
}
211-
const updatePayload = create(nativeProps, this.viewConfig.validAttributes);
212-
213-
const node = getShadowNodeFromInternalInstanceHandle(
214-
this._internalInstanceHandle,
215-
);
216-
if (node != null && updatePayload != null) {
217-
setNativeProps(node, updatePayload);
218-
}
219-
}
220-
}
221-
222-
type ParamOf<Fn> = $Call<<T>((arg: T) => mixed) => T, Fn>;
223-
type ShadowNode = ParamOf<(typeof nativeFabricUIManager)['measure']>;
224-
225-
export function getShadowNodeFromInternalInstanceHandle(
226-
internalInstanceHandle: mixed,
227-
): ?ShadowNode {
228-
return (
229-
// $FlowExpectedError[incompatible-return] internalInstanceHandle is opaque but we need to make an exception here.
230-
internalInstanceHandle &&
231-
// $FlowExpectedError[incompatible-return]
232-
internalInstanceHandle.stateNode &&
233-
// $FlowExpectedError[incompatible-use]
234-
internalInstanceHandle.stateNode.node
235-
);
236-
}
237-
238100
export * from 'react-reconciler/src/ReactFiberHostConfigWithNoMutation';
239101
export * from 'react-reconciler/src/ReactFiberHostConfigWithNoHydration';
240102
export * from 'react-reconciler/src/ReactFiberHostConfigWithNoScopes';
@@ -280,16 +142,21 @@ export function createInstance(
280142
internalInstanceHandle, // internalInstanceHandle
281143
);
282144

283-
const component = new ReactFabricHostComponent(
145+
const component = createPublicInstance(
284146
tag,
285147
viewConfig,
286-
props,
287148
internalInstanceHandle,
288149
);
289150

290151
return {
291152
node: node,
292-
canonical: component,
153+
canonical: {
154+
nativeTag: tag,
155+
viewConfig,
156+
currentProps: props,
157+
internalInstanceHandle,
158+
publicInstance: component,
159+
},
293160
};
294161
}
295162

@@ -359,12 +226,15 @@ export function getChildHostContext(
359226
}
360227

361228
export function getPublicInstance(instance: Instance): null | PublicInstance {
362-
if (instance.canonical) {
363-
return instance.canonical;
229+
if (instance.canonical != null && instance.canonical.publicInstance != null) {
230+
return instance.canonical.publicInstance;
364231
}
365232

366-
// For compatibility with Paper
233+
// For compatibility with the legacy renderer, in case it's used with Fabric
234+
// in the same app.
235+
// $FlowExpectedError[prop-missing]
367236
if (instance._nativeTag != null) {
237+
// $FlowExpectedError[incompatible-return]
368238
return instance;
369239
}
370240

0 commit comments

Comments
 (0)