ReactModalHostView: Prevent infinite SetState/UpdateState loop

Summary:
Make sure to check incoming state values before calling SetState, or we call back and forth forever.

Changelog: [internal]

Reviewed By: mdvacca

Differential Revision: D23389355

fbshipit-source-id: 9cf6110cf654fe93f555a6fbfd9b20f112214e0a
This commit is contained in:
Joshua Gross
2020-08-27 20:00:02 -07:00
committed by Facebook GitHub Bot
parent ab8b77c3d2
commit e60564215d
2 changed files with 29 additions and 2 deletions
@@ -9,6 +9,7 @@ package com.facebook.react.uimanager;
import androidx.annotation.Nullable;
import com.facebook.common.logging.FLog;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.config.ReactFeatureFlags;
@@ -91,4 +92,8 @@ public class FabricViewStateManager {
public void setState(final StateUpdateCallback stateUpdateCallback) {
setState(mStateWrapper, stateUpdateCallback, 0);
}
public @Nullable ReadableMap getState() {
return mStateWrapper != null ? mStateWrapper.getState() : null;
}
}
@@ -28,6 +28,7 @@ import com.facebook.react.R;
import com.facebook.react.bridge.GuardedRunnable;
import com.facebook.react.bridge.LifecycleEventListener;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.UiThreadUtil;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.bridge.WritableNativeMap;
@@ -441,13 +442,34 @@ public class ReactModalHostView extends ViewGroup
@UiThread
public void updateState(final int width, final int height) {
final float realWidth = PixelUtil.toDIPFromPixel(width);
final float realHeight = PixelUtil.toDIPFromPixel(height);
// Check incoming state values. If they're already the correct value, return early to prevent
// infinite UpdateState/SetState loop.
ReadableMap currentState = getFabricViewStateManager().getState();
if (currentState != null) {
float delta = (float) 0.9;
float stateScreenHeight =
currentState.hasKey("screenHeight")
? (float) currentState.getDouble("screenHeight")
: 0;
float stateScreenWidth =
currentState.hasKey("screenWidth") ? (float) currentState.getDouble("screenWidth") : 0;
if (Math.abs(stateScreenWidth - realWidth) < delta
&& Math.abs(stateScreenHeight - realHeight) < delta) {
return;
}
}
mFabricViewStateManager.setState(
new FabricViewStateManager.StateUpdateCallback() {
@Override
public WritableMap getStateUpdate() {
WritableMap map = new WritableNativeMap();
map.putDouble("screenWidth", PixelUtil.toDIPFromPixel(width));
map.putDouble("screenHeight", PixelUtil.toDIPFromPixel(height));
map.putDouble("screenWidth", realWidth);
map.putDouble("screenHeight", realHeight);
return map;
}
});