mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Fix ReactFabricHostComponent methods if detached (#21967)
This commit is contained in:
+26
-14
@@ -137,17 +137,23 @@ class ReactFabricHostComponent {
|
||||
}
|
||||
|
||||
measure(callback: MeasureOnSuccessCallback) {
|
||||
fabricMeasure(
|
||||
this._internalInstanceHandle.stateNode.node,
|
||||
mountSafeCallback_NOT_REALLY_SAFE(this, callback),
|
||||
);
|
||||
const {stateNode} = this._internalInstanceHandle;
|
||||
if (stateNode != null) {
|
||||
fabricMeasure(
|
||||
stateNode.node,
|
||||
mountSafeCallback_NOT_REALLY_SAFE(this, callback),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
measureInWindow(callback: MeasureInWindowOnSuccessCallback) {
|
||||
fabricMeasureInWindow(
|
||||
this._internalInstanceHandle.stateNode.node,
|
||||
mountSafeCallback_NOT_REALLY_SAFE(this, callback),
|
||||
);
|
||||
const {stateNode} = this._internalInstanceHandle;
|
||||
if (stateNode != null) {
|
||||
fabricMeasureInWindow(
|
||||
stateNode.node,
|
||||
mountSafeCallback_NOT_REALLY_SAFE(this, callback),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
measureLayout(
|
||||
@@ -168,12 +174,18 @@ class ReactFabricHostComponent {
|
||||
return;
|
||||
}
|
||||
|
||||
fabricMeasureLayout(
|
||||
this._internalInstanceHandle.stateNode.node,
|
||||
relativeToNativeNode._internalInstanceHandle.stateNode.node,
|
||||
mountSafeCallback_NOT_REALLY_SAFE(this, onFail),
|
||||
mountSafeCallback_NOT_REALLY_SAFE(this, onSuccess),
|
||||
);
|
||||
const toStateNode = this._internalInstanceHandle.stateNode;
|
||||
const fromStateNode =
|
||||
relativeToNativeNode._internalInstanceHandle.stateNode;
|
||||
|
||||
if (toStateNode != null && fromStateNode != null) {
|
||||
fabricMeasureLayout(
|
||||
toStateNode.node,
|
||||
fromStateNode.node,
|
||||
mountSafeCallback_NOT_REALLY_SAFE(this, onFail),
|
||||
mountSafeCallback_NOT_REALLY_SAFE(this, onSuccess),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
setNativeProps(nativeProps: Object) {
|
||||
|
||||
@@ -414,6 +414,37 @@ describe('ReactFabric', () => {
|
||||
expect(successCallback).toHaveBeenCalledWith(10, 10, 100, 100, 0, 0);
|
||||
});
|
||||
|
||||
it('should no-op if calling measure on unmounted refs', () => {
|
||||
const View = createReactNativeComponentClass('RCTView', () => ({
|
||||
validAttributes: {foo: true},
|
||||
uiViewClassName: 'RCTView',
|
||||
}));
|
||||
|
||||
nativeFabricUIManager.measure.mockClear();
|
||||
|
||||
let viewRef;
|
||||
act(() => {
|
||||
ReactFabric.render(
|
||||
<View
|
||||
ref={ref => {
|
||||
viewRef = ref;
|
||||
}}
|
||||
/>,
|
||||
11,
|
||||
);
|
||||
});
|
||||
const dangerouslyRetainedViewRef = viewRef;
|
||||
act(() => {
|
||||
ReactFabric.stopSurface(11);
|
||||
});
|
||||
|
||||
expect(nativeFabricUIManager.measure).not.toBeCalled();
|
||||
const successCallback = jest.fn();
|
||||
dangerouslyRetainedViewRef.measure(successCallback);
|
||||
expect(nativeFabricUIManager.measure).not.toBeCalled();
|
||||
expect(successCallback).not.toBeCalled();
|
||||
});
|
||||
|
||||
it('should call FabricUIManager.measureInWindow on ref.measureInWindow', () => {
|
||||
const View = createReactNativeComponentClass('RCTView', () => ({
|
||||
validAttributes: {foo: true},
|
||||
@@ -442,6 +473,37 @@ describe('ReactFabric', () => {
|
||||
expect(successCallback).toHaveBeenCalledWith(10, 10, 100, 100);
|
||||
});
|
||||
|
||||
it('should no-op if calling measureInWindow on unmounted refs', () => {
|
||||
const View = createReactNativeComponentClass('RCTView', () => ({
|
||||
validAttributes: {foo: true},
|
||||
uiViewClassName: 'RCTView',
|
||||
}));
|
||||
|
||||
nativeFabricUIManager.measureInWindow.mockClear();
|
||||
|
||||
let viewRef;
|
||||
act(() => {
|
||||
ReactFabric.render(
|
||||
<View
|
||||
ref={ref => {
|
||||
viewRef = ref;
|
||||
}}
|
||||
/>,
|
||||
11,
|
||||
);
|
||||
});
|
||||
const dangerouslyRetainedViewRef = viewRef;
|
||||
act(() => {
|
||||
ReactFabric.stopSurface(11);
|
||||
});
|
||||
|
||||
expect(nativeFabricUIManager.measureInWindow).not.toBeCalled();
|
||||
const successCallback = jest.fn();
|
||||
dangerouslyRetainedViewRef.measureInWindow(successCallback);
|
||||
expect(nativeFabricUIManager.measureInWindow).not.toBeCalled();
|
||||
expect(successCallback).not.toBeCalled();
|
||||
});
|
||||
|
||||
it('should support ref in ref.measureLayout', () => {
|
||||
const View = createReactNativeComponentClass('RCTView', () => ({
|
||||
validAttributes: {foo: true},
|
||||
@@ -480,6 +542,119 @@ describe('ReactFabric', () => {
|
||||
expect(successCallback).toHaveBeenCalledWith(1, 1, 100, 100);
|
||||
});
|
||||
|
||||
it('should no-op if calling measureLayout on unmounted "from" ref', () => {
|
||||
const View = createReactNativeComponentClass('RCTView', () => ({
|
||||
validAttributes: {foo: true},
|
||||
uiViewClassName: 'RCTView',
|
||||
}));
|
||||
|
||||
nativeFabricUIManager.measureLayout.mockClear();
|
||||
|
||||
let viewRef;
|
||||
let otherRef;
|
||||
act(() => {
|
||||
ReactFabric.render(
|
||||
<View>
|
||||
<View
|
||||
foo="bar"
|
||||
ref={ref => {
|
||||
viewRef = ref;
|
||||
}}
|
||||
/>
|
||||
<View
|
||||
ref={ref => {
|
||||
otherRef = ref;
|
||||
}}
|
||||
/>
|
||||
</View>,
|
||||
11,
|
||||
);
|
||||
});
|
||||
const dangerouslyRetainedOtherRef = otherRef;
|
||||
act(() => {
|
||||
ReactFabric.render(
|
||||
<View>
|
||||
<View
|
||||
foo="bar"
|
||||
ref={ref => {
|
||||
viewRef = ref;
|
||||
}}
|
||||
/>
|
||||
{null}
|
||||
</View>,
|
||||
11,
|
||||
);
|
||||
});
|
||||
|
||||
expect(nativeFabricUIManager.measureLayout).not.toBeCalled();
|
||||
const successCallback = jest.fn();
|
||||
const failureCallback = jest.fn();
|
||||
viewRef.measureLayout(
|
||||
dangerouslyRetainedOtherRef,
|
||||
successCallback,
|
||||
failureCallback,
|
||||
);
|
||||
expect(nativeFabricUIManager.measureLayout).not.toBeCalled();
|
||||
expect(successCallback).not.toBeCalled();
|
||||
expect(failureCallback).not.toBeCalled();
|
||||
});
|
||||
|
||||
it('should no-op if calling measureLayout on unmounted "to" ref', () => {
|
||||
const View = createReactNativeComponentClass('RCTView', () => ({
|
||||
validAttributes: {foo: true},
|
||||
uiViewClassName: 'RCTView',
|
||||
}));
|
||||
|
||||
nativeFabricUIManager.measureLayout.mockClear();
|
||||
|
||||
let viewRef;
|
||||
let otherRef;
|
||||
act(() => {
|
||||
ReactFabric.render(
|
||||
<View>
|
||||
<View
|
||||
foo="bar"
|
||||
ref={ref => {
|
||||
viewRef = ref;
|
||||
}}
|
||||
/>
|
||||
<View
|
||||
ref={ref => {
|
||||
otherRef = ref;
|
||||
}}
|
||||
/>
|
||||
</View>,
|
||||
11,
|
||||
);
|
||||
});
|
||||
const dangerouslyRetainedViewRef = viewRef;
|
||||
act(() => {
|
||||
ReactFabric.render(
|
||||
<View>
|
||||
{null}
|
||||
<View
|
||||
ref={ref => {
|
||||
otherRef = ref;
|
||||
}}
|
||||
/>
|
||||
</View>,
|
||||
11,
|
||||
);
|
||||
});
|
||||
|
||||
expect(nativeFabricUIManager.measureLayout).not.toBeCalled();
|
||||
const successCallback = jest.fn();
|
||||
const failureCallback = jest.fn();
|
||||
dangerouslyRetainedViewRef.measureLayout(
|
||||
otherRef,
|
||||
successCallback,
|
||||
failureCallback,
|
||||
);
|
||||
expect(nativeFabricUIManager.measureLayout).not.toBeCalled();
|
||||
expect(successCallback).not.toBeCalled();
|
||||
expect(failureCallback).not.toBeCalled();
|
||||
});
|
||||
|
||||
it('returns the correct instance and calls it in the callback', () => {
|
||||
const View = createReactNativeComponentClass('RCTView', () => ({
|
||||
validAttributes: {foo: true},
|
||||
|
||||
Reference in New Issue
Block a user