Skip to content
Merged
121 changes: 106 additions & 15 deletions packages/react-native-renderer/src/NativeMethodsMixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import type {
import invariant from 'shared/invariant';
// Modules provided by RN:
import TextInputState from 'TextInputState';
import * as FabricUIManager from 'FabricUIManager';
import UIManager from 'UIManager';

import {create} from './ReactNativeAttributePayload';
Expand Down Expand Up @@ -68,10 +69,33 @@ export default function(
* prop](docs/view.html#onlayout) instead.
*/
measure: function(callback: MeasureOnSuccessCallback) {
UIManager.measure(
findNodeHandle(this),
mountSafeCallback_NOT_REALLY_SAFE(this, callback),
);
let maybeInstance;

// Fiber errors if findNodeHandle is called for an umounted component.
// Tests using ReactTestRenderer will trigger this case indirectly.
// Mimicking stack behavior, we should silently ignore this case.
// TODO Fix ReactTestRenderer so we can remove this try/catch.
try {
maybeInstance = findHostInstance(this);
} catch (error) {}

// If there is no host component beneath this we should fail silently.
// This is not an error; it could mean a class component rendered null.
if (maybeInstance == null) {
return;
}

if (maybeInstance.canonical) {
FabricUIManager.measure(
maybeInstance.node,
mountSafeCallback_NOT_REALLY_SAFE(this, callback),
);
} else {
UIManager.measure(
findNodeHandle(this),
mountSafeCallback_NOT_REALLY_SAFE(this, callback),
);
}
},

/**
Expand All @@ -90,10 +114,33 @@ export default function(
* has been completed in native.
*/
measureInWindow: function(callback: MeasureInWindowOnSuccessCallback) {
UIManager.measureInWindow(
findNodeHandle(this),
mountSafeCallback_NOT_REALLY_SAFE(this, callback),
);
let maybeInstance;

// Fiber errors if findNodeHandle is called for an umounted component.
// Tests using ReactTestRenderer will trigger this case indirectly.
// Mimicking stack behavior, we should silently ignore this case.
// TODO Fix ReactTestRenderer so we can remove this try/catch.
try {
maybeInstance = findHostInstance(this);
} catch (error) {}

// If there is no host component beneath this we should fail silently.
// This is not an error; it could mean a class component rendered null.
if (maybeInstance == null) {
return;
}

if (maybeInstance.canonical) {
FabricUIManager.measureInWindow(
maybeInstance.node,
mountSafeCallback_NOT_REALLY_SAFE(this, callback),
);
} else {
UIManager.measureInWindow(
findNodeHandle(this),
mountSafeCallback_NOT_REALLY_SAFE(this, callback),
);
}
},

/**
Expand All @@ -105,16 +152,60 @@ export default function(
* `findNodeHandle(component)`.
*/
measureLayout: function(
relativeToNativeNode: number,
relativeToNativeNode: number | Object,
onSuccess: MeasureLayoutOnSuccessCallback,
onFail: () => void /* currently unused */,
) {
UIManager.measureLayout(
findNodeHandle(this),
relativeToNativeNode,
mountSafeCallback_NOT_REALLY_SAFE(this, onFail),
mountSafeCallback_NOT_REALLY_SAFE(this, onSuccess),
);
let maybeInstance;

// Fiber errors if findNodeHandle is called for an umounted component.
// Tests using ReactTestRenderer will trigger this case indirectly.
// Mimicking stack behavior, we should silently ignore this case.
// TODO Fix ReactTestRenderer so we can remove this try/catch.
try {
maybeInstance = findHostInstance(this);
} catch (error) {}

// If there is no host component beneath this we should fail silently.
// This is not an error; it could mean a class component rendered null.
if (maybeInstance == null) {
return;
}

if (maybeInstance.canonical) {
warningWithoutStack(
false,
'Warning: measureLayout on components using NativeMethodsMixin ' +
'or ReactNative.NativeComponent is not currently supported in Fabric. ' +
'measureLayout must be called on a native ref. Consider using forwardRef.',
);
return;
} else {
let relativeNode;

if (typeof relativeToNativeNode === 'number') {
// Already a node handle
relativeNode = relativeToNativeNode;
} else if (relativeToNativeNode._nativeTag) {
relativeNode = relativeToNativeNode._nativeTag;
}

if (relativeNode == null) {
warningWithoutStack(
false,
'Warning: ref.measureLayout must be called with a node handle or a ref to a native component.',
);

return;
}

UIManager.measureLayout(
findNodeHandle(this),
relativeNode,
mountSafeCallback_NOT_REALLY_SAFE(this, onFail),
mountSafeCallback_NOT_REALLY_SAFE(this, onSuccess),
);
}
},

/**
Expand Down
47 changes: 23 additions & 24 deletions packages/react-native-renderer/src/ReactFabricHostConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,10 @@ import {
appendChildToSet as appendChildNodeToSet,
completeRoot,
registerEventHandler,
measure as fabricMeasure,
measureInWindow as fabricMeasureInWindow,
measureLayout as fabricMeasureLayout,
} from 'FabricUIManager';
import UIManager from 'UIManager';

// Counter for uniquely identifying views.
// % 10 === 1 means it is a rootTag.
Expand Down Expand Up @@ -85,15 +87,18 @@ class ReactFabricHostComponent {
_nativeTag: number;
viewConfig: ReactNativeBaseComponentViewConfig<>;
currentProps: Props;
_internalInstanceHandle: Object;

constructor(
tag: number,
viewConfig: ReactNativeBaseComponentViewConfig<>,
props: Props,
internalInstanceHandle: Object,
) {
this._nativeTag = tag;
this.viewConfig = viewConfig;
this.currentProps = props;
this._internalInstanceHandle = internalInstanceHandle;
}

blur() {
Expand All @@ -105,15 +110,15 @@ class ReactFabricHostComponent {
}

measure(callback: MeasureOnSuccessCallback) {
UIManager.measure(
this._nativeTag,
fabricMeasure(
this._internalInstanceHandle.stateNode.node,
mountSafeCallback_NOT_REALLY_SAFE(this, callback),
);
}

measureInWindow(callback: MeasureInWindowOnSuccessCallback) {
UIManager.measureInWindow(
this._nativeTag,
fabricMeasureInWindow(
this._internalInstanceHandle.stateNode.node,
mountSafeCallback_NOT_REALLY_SAFE(this, callback),
);
}
Expand All @@ -123,32 +128,21 @@ class ReactFabricHostComponent {
onSuccess: MeasureLayoutOnSuccessCallback,
onFail: () => void /* currently unused */,
) {
let relativeNode;

if (typeof relativeToNativeNode === 'number') {
// Already a node handle
relativeNode = relativeToNativeNode;
} else if (relativeToNativeNode._nativeTag) {
relativeNode = relativeToNativeNode._nativeTag;
} else if (
relativeToNativeNode.canonical &&
relativeToNativeNode.canonical._nativeTag
if (
typeof relativeToNativeNode === 'number' ||
!(relativeToNativeNode instanceof ReactFabricHostComponent)
) {
relativeNode = relativeToNativeNode.canonical._nativeTag;
}

if (relativeNode == null) {
warningWithoutStack(
false,
'Warning: ref.measureLayout must be called with a node handle or a ref to a native component.',
'Warning: ref.measureLayout must be called with a ref to a native component.',
);

return;
}

UIManager.measureLayout(
this._nativeTag,
relativeNode,
fabricMeasureLayout(
this._internalInstanceHandle.stateNode.node,
relativeToNativeNode._internalInstanceHandle.stateNode.node,
mountSafeCallback_NOT_REALLY_SAFE(this, onFail),
mountSafeCallback_NOT_REALLY_SAFE(this, onSuccess),
);
Expand Down Expand Up @@ -212,7 +206,12 @@ export function createInstance(
internalInstanceHandle, // internalInstanceHandle
);

const component = new ReactFabricHostComponent(tag, viewConfig, props);
const component = new ReactFabricHostComponent(
tag,
viewConfig,
props,
internalInstanceHandle,
);

return {
node: node,
Expand Down
Loading