Refactor ReactFabricHostComponent (#26323)
## Summary This is a small refactor of `ReactFabricHostComponent` to remove unnecessary dependencies, unused methods and type definitions to simplify a larger refactor of the class in a following PR (https://github.com/facebook/react/pull/26321). ## How did you test this change? Existing unit tests.
Rubén Norte committed
Mar 7, 2023 at 14:33 UTC
8f812e75d6bfe57448a6ef900a0375f5acc4cee5
6 files changed
+83
-76
packages/react-native-renderer/src/NativeMethodsMixinUtils.js
-20
@@ -45,26 +45,6 @@ export function mountSafeCallback_NOT_REALLY_SAFE(
45
};
46
}
47
48
-export function throwOnStylesProp(component: any, props: any) {
49
- if (props.styles !== undefined) {
50
- const owner = component._owner || null;
51
- const name = component.constructor.displayName;
52
- let msg =
53
- '`styles` is not a supported property of `' +
54
- name +
55
- '`, did ' +
56
- 'you mean `style` (singular)?';
57
- if (owner && owner.constructor && owner.constructor.displayName) {
58
- msg +=
59
- '\n\nCheck the `' +
60
- owner.constructor.displayName +
61
- '` parent ' +
62
- ' component.';
63
- }
64
- throw new Error(msg);
65
- }
66
-}
67
-
48
export function warnForStyleProps(props: any, validAttributes: any) {
49
if (__DEV__) {
50
for (const key in validAttributes.style) {
packages/react-native-renderer/src/ReactFabric.js
+1
@@ -122,6 +122,7 @@ export {
122
};
123
124
injectIntoDevTools({
125
+ // $FlowExpectedError[incompatible-call] The type of `Instance` in `getClosestInstanceFromNode` does not match in Fabric and the legacy renderer, so it fails to typecheck here.
126
findFiberByHostInstance: getClosestInstanceFromNode,
127
bundleType: __DEV__ ? 1 : 0,
128
version: ReactVersion,
packages/react-native-renderer/src/ReactFabricComponentTree.js
+30
-14
@@ -3,28 +3,44 @@
3
*
4
* This source code is licensed under the MIT license found in the
5
* LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @flow strict-local
8
*/
9
8
-function getInstanceFromInstance(instanceHandle) {
9
- return instanceHandle;
10
+import type {
11
+ PublicInstance,
12
+ Instance,
13
+ Props,
14
+ TextInstance,
15
+} from './ReactFabricHostConfig';
16
+import type {Fiber} from 'react-reconciler/src/ReactInternalTypes';
17
+import {getPublicInstance} from './ReactFabricHostConfig';
18
+
19
+// `node` is typed incorrectly here. The proper type should be `PublicInstance`.
20
+// This is ok in DOM because they types are interchangeable, but in React Native
21
+// they aren't.
22
+function getInstanceFromNode(node: Instance | TextInstance): Fiber | null {
23
+ // $FlowFixMe[incompatible-return] DevTools incorrectly passes a fiber in React Native.
24
+ return node;
25
}
26
12
-function getTagFromInstance(inst) {
13
- const nativeInstance = inst.stateNode.canonical;
27
+function getNodeFromInstance(fiber: Fiber): PublicInstance {
28
+ const publicInstance = getPublicInstance(fiber.stateNode);
29
15
- if (!nativeInstance._nativeTag) {
16
- throw new Error('All native instances should have a tag.');
30
+ if (publicInstance == null) {
31
+ throw new Error('Could not find host instance from fiber');
32
}
33
19
- return nativeInstance;
34
+ return publicInstance;
35
+}
36
+
37
+function getFiberCurrentPropsFromNode(instance: Instance): Props {
38
+ return instance.canonical.currentProps;
39
}
40
41
export {
23
- getInstanceFromInstance as getClosestInstanceFromNode,
24
- getInstanceFromInstance as getInstanceFromNode,
25
- getTagFromInstance as getNodeFromInstance,
42
+ getInstanceFromNode,
43
+ getInstanceFromNode as getClosestInstanceFromNode,
44
+ getNodeFromInstance,
45
+ getFiberCurrentPropsFromNode,
46
};
27
-
28
-export function getFiberCurrentPropsFromNode(inst) {
29
- return inst.canonical.currentProps;
30
-}
packages/react-native-renderer/src/ReactFabricEventEmitter.js
+3
-1
@@ -29,6 +29,7 @@ import getListener from './ReactNativeGetListener';
29
import {runEventsInBatch} from './legacy-events/EventBatching';
30
31
import {RawEventEmitter} from 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface';
32
+import {getPublicInstance} from './ReactFabricHostConfig';
33
34
export {getListener, registrationNameModules as registrationNames};
35
@@ -92,7 +93,8 @@ export function dispatchEvent(
93
const stateNode = targetFiber.stateNode;
94
// Guard against Fiber being unmounted
95
if (stateNode != null) {
95
- eventTarget = stateNode.canonical;
96
+ // $FlowExpectedError[incompatible-cast] public instances in Fabric do not implement `EventTarget` yet.
97
+ eventTarget = (getPublicInstance(stateNode): EventTarget);
98
}
99
}
100
packages/react-native-renderer/src/ReactFabricHostConfig.js
+49
-29
@@ -18,10 +18,7 @@ import type {
18
TouchedViewDataAtPoint,
19
} from './ReactNativeTypes';
20
21
-import {
22
- mountSafeCallback_NOT_REALLY_SAFE,
23
- warnForStyleProps,
24
-} from './NativeMethodsMixinUtils';
21
+import {warnForStyleProps} from './NativeMethodsMixinUtils';
22
import {create, diff} from './ReactNativeAttributePayload';
23
24
import {dispatchEvent} from './ReactFabricEventEmitter';
@@ -107,6 +104,8 @@ if (registerEventHandler) {
104
registerEventHandler(dispatchEvent);
105
}
106
107
+const noop = () => {};
108
+
109
/**
110
* This is used for refs on host components.
111
*/
@@ -137,22 +136,20 @@ class ReactFabricHostComponent implements NativeMethods {
136
}
137
138
measure(callback: MeasureOnSuccessCallback) {
140
- const {stateNode} = this._internalInstanceHandle;
141
- if (stateNode != null) {
142
- fabricMeasure(
143
- stateNode.node,
144
- mountSafeCallback_NOT_REALLY_SAFE(this, callback),
145
- );
139
+ const node = getShadowNodeFromInternalInstanceHandle(
140
+ this._internalInstanceHandle,
141
+ );
142
+ if (node != null) {
143
+ fabricMeasure(node, callback);
144
}
145
}
146
147
measureInWindow(callback: MeasureInWindowOnSuccessCallback) {
150
- const {stateNode} = this._internalInstanceHandle;
151
- if (stateNode != null) {
152
- fabricMeasureInWindow(
153
- stateNode.node,
154
- mountSafeCallback_NOT_REALLY_SAFE(this, callback),
155
- );
148
+ const node = getShadowNodeFromInternalInstanceHandle(
149
+ this._internalInstanceHandle,
150
+ );
151
+ if (node != null) {
152
+ fabricMeasureInWindow(node, callback);
153
}
154
}
155
@@ -174,24 +171,29 @@ class ReactFabricHostComponent implements NativeMethods {
171
return;
172
}
173
177
- const toStateNode = this._internalInstanceHandle.stateNode;
178
- const fromStateNode =
179
- relativeToNativeNode._internalInstanceHandle.stateNode;
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.node,
184
- fromStateNode.node,
185
- mountSafeCallback_NOT_REALLY_SAFE(this, onFail),
186
- mountSafeCallback_NOT_REALLY_SAFE(this, onSuccess),
183
+ toStateNode,
184
+ fromStateNode,
185
+ onFail != null ? onFail : noop,
186
+ onSuccess != null ? onSuccess : noop,
187
);
188
}
189
}
190
191
unstable_getBoundingClientRect(): DOMRect {
192
- const {stateNode} = this._internalInstanceHandle;
193
- if (stateNode != null) {
194
- const rect = fabricGetBoundingClientRect(stateNode.node);
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]);
@@ -208,13 +210,31 @@ class ReactFabricHostComponent implements NativeMethods {
210
}
211
const updatePayload = create(nativeProps, this.viewConfig.validAttributes);
212
211
- const {stateNode} = this._internalInstanceHandle;
212
- if (stateNode != null && updatePayload != null) {
213
- setNativeProps(stateNode.node, updatePayload);
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
+
238
export * from 'react-reconciler/src/ReactFiberHostConfigWithNoMutation';
239
export * from 'react-reconciler/src/ReactFiberHostConfigWithNoHydration';
240
export * from 'react-reconciler/src/ReactFiberHostConfigWithNoScopes';
packages/react-native-renderer/src/ReactNativeTypes.js
-12
@@ -218,18 +218,6 @@ export type ReactFabricType = {
218
...
219
};
220
221
-export type ReactNativeEventTarget = {
222
- node: {...},
223
- canonical: {
224
- _nativeTag: number,
225
- viewConfig: ViewConfig,
226
- currentProps: {...},
227
- _internalInstanceHandle: {...},
228
- ...
229
- },
230
- ...
231
-};
232
-
221
export type ReactFabricEventTouch = {
222
identifier: number,
223
locationX: number,