@samitouri / QOS-React-2 / commits / 8f812e75d6

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,