Skip to content

Commit 01b5c1e

Browse files
committed
Extracted definition and access to public instances to a separate module in Fabric
1 parent 3b0f006 commit 01b5c1e

10 files changed

+334
-197
lines changed

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

Lines changed: 10 additions & 1 deletion
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.internals != null &&
27+
instance.internals.internalInstanceHandle != null
28+
) {
29+
return instance.internals.internalInstanceHandle;
30+
}
31+
2332
// $FlowFixMe[incompatible-return] DevTools incorrectly passes a fiber in React Native.
2433
return node;
2534
}
@@ -35,7 +44,7 @@ function getNodeFromInstance(fiber: Fiber): PublicInstance {
3544
}
3645

3746
function getFiberCurrentPropsFromNode(instance: Instance): Props {
38-
return instance.canonical.currentProps;
47+
return instance && instance.internals && instance.internals.currentProps;
3948
}
4049

4150
export {

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

Lines changed: 37 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-
NativeMethods,
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,18 @@ 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+
// Exposed through refs.
59+
publicInstance: ReactFabricHostComponent,
60+
// We define this as an object instead of as separate fields to simplify
61+
// making copies of instance where `internals` don't change.
62+
internals: {
63+
nativeTag: number,
64+
viewConfig: ViewConfig,
65+
currentProps: Props,
66+
internalInstanceHandle: Object,
67+
},
7468
};
7569
export type TextInstance = {node: Node, ...};
7670
export type HydratableInstance = Instance | TextInstance;
@@ -104,137 +98,6 @@ if (registerEventHandler) {
10498
registerEventHandler(dispatchEvent);
10599
}
106100

107-
const noop = () => {};
108-
109-
/**
110-
* This is used for refs on host components.
111-
*/
112-
class ReactFabricHostComponent implements NativeMethods {
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-
238101
export * from 'react-reconciler/src/ReactFiberHostConfigWithNoMutation';
239102
export * from 'react-reconciler/src/ReactFiberHostConfigWithNoHydration';
240103
export * from 'react-reconciler/src/ReactFiberHostConfigWithNoScopes';
@@ -280,16 +143,21 @@ export function createInstance(
280143
internalInstanceHandle, // internalInstanceHandle
281144
);
282145

283-
const component = new ReactFabricHostComponent(
146+
const component = createPublicInstance(
284147
tag,
285148
viewConfig,
286-
props,
287149
internalInstanceHandle,
288150
);
289151

290152
return {
291153
node: node,
292-
canonical: component,
154+
publicInstance: component,
155+
internals: {
156+
nativeTag: tag,
157+
viewConfig,
158+
currentProps: props,
159+
internalInstanceHandle,
160+
},
293161
};
294162
}
295163

@@ -359,12 +227,15 @@ export function getChildHostContext(
359227
}
360228

361229
export function getPublicInstance(instance: Instance): null | PublicInstance {
362-
if (instance.canonical) {
363-
return instance.canonical;
230+
if (instance.publicInstance != null) {
231+
return instance.publicInstance;
364232
}
365233

366-
// For compatibility with Paper
234+
// For compatibility with the legacy renderer, in case it's used with Fabric
235+
// in the same app.
236+
// $FlowExpectedError[prop-missing]
367237
if (instance._nativeTag != null) {
238+
// $FlowExpectedError[incompatible-return]
368239
return instance;
369240
}
370241

@@ -383,12 +254,12 @@ export function prepareUpdate(
383254
newProps: Props,
384255
hostContext: HostContext,
385256
): null | Object {
386-
const viewConfig = instance.canonical.viewConfig;
257+
const viewConfig = instance.internals.viewConfig;
387258
const updatePayload = diff(oldProps, newProps, viewConfig.validAttributes);
388259
// TODO: If the event handlers have changed, we need to update the current props
389260
// in the commit phase but there is no host config hook to do it yet.
390261
// So instead we hack it by updating it in the render phase.
391-
instance.canonical.currentProps = newProps;
262+
instance.internals.currentProps = newProps;
392263
return updatePayload;
393264
}
394265

@@ -467,7 +338,8 @@ export function cloneInstance(
467338
}
468339
return {
469340
node: clone,
470-
canonical: instance.canonical,
341+
publicInstance: instance.publicInstance,
342+
internals: instance.internals,
471343
};
472344
}
473345

@@ -477,15 +349,16 @@ export function cloneHiddenInstance(
477349
props: Props,
478350
internalInstanceHandle: Object,
479351
): Instance {
480-
const viewConfig = instance.canonical.viewConfig;
352+
const viewConfig = instance.internals.viewConfig;
481353
const node = instance.node;
482354
const updatePayload = create(
483355
{style: {display: 'none'}},
484356
viewConfig.validAttributes,
485357
);
486358
return {
487359
node: cloneNodeWithNewProps(node, updatePayload),
488-
canonical: instance.canonical,
360+
publicInstance: instance.publicInstance,
361+
internals: instance.internals,
489362
};
490363
}
491364

0 commit comments

Comments
 (0)