Skip to content

Commit

Permalink
Refactor ReactFabricHostComponent (#26323)
Browse files Browse the repository at this point in the history
## 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
(#26321).

## How did you test this change?

Existing unit tests.
  • Loading branch information
rubennorte authored Mar 7, 2023
1 parent 978fae4 commit 8f812e7
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 76 deletions.
20 changes: 0 additions & 20 deletions packages/react-native-renderer/src/NativeMethodsMixinUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,26 +45,6 @@ export function mountSafeCallback_NOT_REALLY_SAFE(
};
}

export function throwOnStylesProp(component: any, props: any) {
if (props.styles !== undefined) {
const owner = component._owner || null;
const name = component.constructor.displayName;
let msg =
'`styles` is not a supported property of `' +
name +
'`, did ' +
'you mean `style` (singular)?';
if (owner && owner.constructor && owner.constructor.displayName) {
msg +=
'\n\nCheck the `' +
owner.constructor.displayName +
'` parent ' +
' component.';
}
throw new Error(msg);
}
}

export function warnForStyleProps(props: any, validAttributes: any) {
if (__DEV__) {
for (const key in validAttributes.style) {
Expand Down
1 change: 1 addition & 0 deletions packages/react-native-renderer/src/ReactFabric.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ export {
};

injectIntoDevTools({
// $FlowExpectedError[incompatible-call] The type of `Instance` in `getClosestInstanceFromNode` does not match in Fabric and the legacy renderer, so it fails to typecheck here.
findFiberByHostInstance: getClosestInstanceFromNode,
bundleType: __DEV__ ? 1 : 0,
version: ReactVersion,
Expand Down
44 changes: 30 additions & 14 deletions packages/react-native-renderer/src/ReactFabricComponentTree.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,44 @@
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
*/

function getInstanceFromInstance(instanceHandle) {
return instanceHandle;
import type {
PublicInstance,
Instance,
Props,
TextInstance,
} from './ReactFabricHostConfig';
import type {Fiber} from 'react-reconciler/src/ReactInternalTypes';
import {getPublicInstance} from './ReactFabricHostConfig';

// `node` is typed incorrectly here. The proper type should be `PublicInstance`.
// This is ok in DOM because they types are interchangeable, but in React Native
// they aren't.
function getInstanceFromNode(node: Instance | TextInstance): Fiber | null {
// $FlowFixMe[incompatible-return] DevTools incorrectly passes a fiber in React Native.
return node;
}

function getTagFromInstance(inst) {
const nativeInstance = inst.stateNode.canonical;
function getNodeFromInstance(fiber: Fiber): PublicInstance {
const publicInstance = getPublicInstance(fiber.stateNode);

if (!nativeInstance._nativeTag) {
throw new Error('All native instances should have a tag.');
if (publicInstance == null) {
throw new Error('Could not find host instance from fiber');
}

return nativeInstance;
return publicInstance;
}

function getFiberCurrentPropsFromNode(instance: Instance): Props {
return instance.canonical.currentProps;
}

export {
getInstanceFromInstance as getClosestInstanceFromNode,
getInstanceFromInstance as getInstanceFromNode,
getTagFromInstance as getNodeFromInstance,
getInstanceFromNode,
getInstanceFromNode as getClosestInstanceFromNode,
getNodeFromInstance,
getFiberCurrentPropsFromNode,
};

export function getFiberCurrentPropsFromNode(inst) {
return inst.canonical.currentProps;
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import getListener from './ReactNativeGetListener';
import {runEventsInBatch} from './legacy-events/EventBatching';

import {RawEventEmitter} from 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface';
import {getPublicInstance} from './ReactFabricHostConfig';

export {getListener, registrationNameModules as registrationNames};

Expand Down Expand Up @@ -92,7 +93,8 @@ export function dispatchEvent(
const stateNode = targetFiber.stateNode;
// Guard against Fiber being unmounted
if (stateNode != null) {
eventTarget = stateNode.canonical;
// $FlowExpectedError[incompatible-cast] public instances in Fabric do not implement `EventTarget` yet.
eventTarget = (getPublicInstance(stateNode): EventTarget);
}
}

Expand Down
78 changes: 49 additions & 29 deletions packages/react-native-renderer/src/ReactFabricHostConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,7 @@ import type {
TouchedViewDataAtPoint,
} from './ReactNativeTypes';

import {
mountSafeCallback_NOT_REALLY_SAFE,
warnForStyleProps,
} from './NativeMethodsMixinUtils';
import {warnForStyleProps} from './NativeMethodsMixinUtils';
import {create, diff} from './ReactNativeAttributePayload';

import {dispatchEvent} from './ReactFabricEventEmitter';
Expand Down Expand Up @@ -107,6 +104,8 @@ if (registerEventHandler) {
registerEventHandler(dispatchEvent);
}

const noop = () => {};

/**
* This is used for refs on host components.
*/
Expand Down Expand Up @@ -137,22 +136,20 @@ class ReactFabricHostComponent implements NativeMethods {
}

measure(callback: MeasureOnSuccessCallback) {
const {stateNode} = this._internalInstanceHandle;
if (stateNode != null) {
fabricMeasure(
stateNode.node,
mountSafeCallback_NOT_REALLY_SAFE(this, callback),
);
const node = getShadowNodeFromInternalInstanceHandle(
this._internalInstanceHandle,
);
if (node != null) {
fabricMeasure(node, callback);
}
}

measureInWindow(callback: MeasureInWindowOnSuccessCallback) {
const {stateNode} = this._internalInstanceHandle;
if (stateNode != null) {
fabricMeasureInWindow(
stateNode.node,
mountSafeCallback_NOT_REALLY_SAFE(this, callback),
);
const node = getShadowNodeFromInternalInstanceHandle(
this._internalInstanceHandle,
);
if (node != null) {
fabricMeasureInWindow(node, callback);
}
}

Expand All @@ -174,24 +171,29 @@ class ReactFabricHostComponent implements NativeMethods {
return;
}

const toStateNode = this._internalInstanceHandle.stateNode;
const fromStateNode =
relativeToNativeNode._internalInstanceHandle.stateNode;
const toStateNode = getShadowNodeFromInternalInstanceHandle(
this._internalInstanceHandle,
);
const fromStateNode = getShadowNodeFromInternalInstanceHandle(
relativeToNativeNode._internalInstanceHandle,
);

if (toStateNode != null && fromStateNode != null) {
fabricMeasureLayout(
toStateNode.node,
fromStateNode.node,
mountSafeCallback_NOT_REALLY_SAFE(this, onFail),
mountSafeCallback_NOT_REALLY_SAFE(this, onSuccess),
toStateNode,
fromStateNode,
onFail != null ? onFail : noop,
onSuccess != null ? onSuccess : noop,
);
}
}

unstable_getBoundingClientRect(): DOMRect {
const {stateNode} = this._internalInstanceHandle;
if (stateNode != null) {
const rect = fabricGetBoundingClientRect(stateNode.node);
const node = getShadowNodeFromInternalInstanceHandle(
this._internalInstanceHandle,
);
if (node != null) {
const rect = fabricGetBoundingClientRect(node);

if (rect) {
return new DOMRect(rect[0], rect[1], rect[2], rect[3]);
Expand All @@ -208,13 +210,31 @@ class ReactFabricHostComponent implements NativeMethods {
}
const updatePayload = create(nativeProps, this.viewConfig.validAttributes);

const {stateNode} = this._internalInstanceHandle;
if (stateNode != null && updatePayload != null) {
setNativeProps(stateNode.node, updatePayload);
const node = getShadowNodeFromInternalInstanceHandle(
this._internalInstanceHandle,
);
if (node != null && updatePayload != null) {
setNativeProps(node, updatePayload);
}
}
}

type ParamOf<Fn> = $Call<<T>((arg: T) => mixed) => T, Fn>;
type ShadowNode = ParamOf<(typeof nativeFabricUIManager)['measure']>;

export function getShadowNodeFromInternalInstanceHandle(
internalInstanceHandle: mixed,
): ?ShadowNode {
return (
// $FlowExpectedError[incompatible-return] internalInstanceHandle is opaque but we need to make an exception here.
internalInstanceHandle &&
// $FlowExpectedError[incompatible-return]
internalInstanceHandle.stateNode &&
// $FlowExpectedError[incompatible-use]
internalInstanceHandle.stateNode.node
);
}

export * from 'react-reconciler/src/ReactFiberHostConfigWithNoMutation';
export * from 'react-reconciler/src/ReactFiberHostConfigWithNoHydration';
export * from 'react-reconciler/src/ReactFiberHostConfigWithNoScopes';
Expand Down
12 changes: 0 additions & 12 deletions packages/react-native-renderer/src/ReactNativeTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -218,18 +218,6 @@ export type ReactFabricType = {
...
};

export type ReactNativeEventTarget = {
node: {...},
canonical: {
_nativeTag: number,
viewConfig: ViewConfig,
currentProps: {...},
_internalInstanceHandle: {...},
...
},
...
};

export type ReactFabricEventTouch = {
identifier: number,
locationX: number,
Expand Down

0 comments on commit 8f812e7

Please sign in to comment.