Skip to content

Commit a51ca5f

Browse files
committed
Extracted definition and access to public instances to a separate module in Fabric
1 parent d1ad984 commit a51ca5f

13 files changed

+392
-213
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: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ 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 (instance.internalInstanceHandle != null) {
26+
return instance.internalInstanceHandle;
27+
}
28+
2329
// $FlowFixMe[incompatible-return] DevTools incorrectly passes a fiber in React Native.
2430
return node;
2531
}
@@ -35,7 +41,7 @@ function getNodeFromInstance(fiber: Fiber): PublicInstance {
3541
}
3642

3743
function getFiberCurrentPropsFromNode(instance: Instance): Props {
38-
return instance.canonical.currentProps;
44+
return instance.currentProps;
3945
}
4046

4147
export {

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

Lines changed: 38 additions & 164 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,15 @@ 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+
nativeTag: number,
59+
viewConfig: ViewConfig,
60+
currentProps: Props,
61+
// Reference to the React handle (the fiber)
62+
internalInstanceHandle: Object,
63+
// Exposed through refs.
64+
publicInstance: ReactFabricHostComponent,
7465
};
7566
export type TextInstance = {node: Node, ...};
7667
export type HydratableInstance = Instance | TextInstance;
@@ -104,137 +95,6 @@ if (registerEventHandler) {
10495
registerEventHandler(dispatchEvent);
10596
}
10697

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-
23898
export * from 'react-reconciler/src/ReactFiberHostConfigWithNoMutation';
23999
export * from 'react-reconciler/src/ReactFiberHostConfigWithNoHydration';
240100
export * from 'react-reconciler/src/ReactFiberHostConfigWithNoScopes';
@@ -280,16 +140,19 @@ export function createInstance(
280140
internalInstanceHandle, // internalInstanceHandle
281141
);
282142

283-
const component = new ReactFabricHostComponent(
143+
const component = createPublicInstance(
284144
tag,
285145
viewConfig,
286-
props,
287146
internalInstanceHandle,
288147
);
289148

290149
return {
291150
node: node,
292-
canonical: component,
151+
nativeTag: tag,
152+
viewConfig,
153+
currentProps: props,
154+
internalInstanceHandle,
155+
publicInstance: component,
293156
};
294157
}
295158

@@ -359,12 +222,15 @@ export function getChildHostContext(
359222
}
360223

361224
export function getPublicInstance(instance: Instance): null | PublicInstance {
362-
if (instance.canonical) {
363-
return instance.canonical;
225+
if (instance.publicInstance != null) {
226+
return instance.publicInstance;
364227
}
365228

366-
// For compatibility with Paper
229+
// For compatibility with the legacy renderer, in case it's used with Fabric
230+
// in the same app.
231+
// $FlowExpectedError[prop-missing]
367232
if (instance._nativeTag != null) {
233+
// $FlowExpectedError[incompatible-return]
368234
return instance;
369235
}
370236

@@ -383,12 +249,12 @@ export function prepareUpdate(
383249
newProps: Props,
384250
hostContext: HostContext,
385251
): null | Object {
386-
const viewConfig = instance.canonical.viewConfig;
252+
const viewConfig = instance.viewConfig;
387253
const updatePayload = diff(oldProps, newProps, viewConfig.validAttributes);
388254
// TODO: If the event handlers have changed, we need to update the current props
389255
// in the commit phase but there is no host config hook to do it yet.
390256
// So instead we hack it by updating it in the render phase.
391-
instance.canonical.currentProps = newProps;
257+
instance.currentProps = newProps;
392258
return updatePayload;
393259
}
394260

@@ -467,7 +333,11 @@ export function cloneInstance(
467333
}
468334
return {
469335
node: clone,
470-
canonical: instance.canonical,
336+
nativeTag: instance.nativeTag,
337+
viewConfig: instance.viewConfig,
338+
currentProps: instance.currentProps,
339+
internalInstanceHandle: instance.internalInstanceHandle,
340+
publicInstance: instance.publicInstance,
471341
};
472342
}
473343

@@ -477,15 +347,19 @@ export function cloneHiddenInstance(
477347
props: Props,
478348
internalInstanceHandle: Object,
479349
): Instance {
480-
const viewConfig = instance.canonical.viewConfig;
350+
const viewConfig = instance.viewConfig;
481351
const node = instance.node;
482352
const updatePayload = create(
483353
{style: {display: 'none'}},
484354
viewConfig.validAttributes,
485355
);
486356
return {
487357
node: cloneNodeWithNewProps(node, updatePayload),
488-
canonical: instance.canonical,
358+
nativeTag: instance.nativeTag,
359+
viewConfig: instance.viewConfig,
360+
currentProps: instance.currentProps,
361+
internalInstanceHandle: instance.internalInstanceHandle,
362+
publicInstance: instance.publicInstance,
489363
};
490364
}
491365

0 commit comments

Comments
 (0)