From b08fff6f869e00c20c0dcdf7aca71284c2f276f0 Mon Sep 17 00:00:00 2001 From: Samuel Susla Date: Mon, 27 Jul 2020 13:14:34 -0700 Subject: [PATCH] Fix race condition in KeyboardAvoidingView Summary: Changelog: Fix possible race condition inside `KeyboardAvoidingView` Fabric has different order of events In Fabric, `keyboardWillChangeFrame` event is fired before `onLayout`, but in Paper it is the other way around. `KeyboardAvoidingView` depends on the order of events to function properly. Inside `_relativeKeyboardHeight` 0 is returned if `this._frame` is null. To fix this, `bottom` margin is recalculated whenever `keyboardWillChangeFrame` or `onLayout` is triggered. Reviewed By: shergin Differential Revision: D22764192 fbshipit-source-id: 591ac59af4395a4d43c4e78e4fbc0ff118b292f8 --- .../Keyboard/KeyboardAvoidingView.js | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/Libraries/Components/Keyboard/KeyboardAvoidingView.js b/Libraries/Components/Keyboard/KeyboardAvoidingView.js index b8a150efbaa34d..4e87a3f16c8d76 100644 --- a/Libraries/Components/Keyboard/KeyboardAvoidingView.js +++ b/Libraries/Components/Keyboard/KeyboardAvoidingView.js @@ -67,6 +67,7 @@ class KeyboardAvoidingView extends React.Component { }; _frame: ?ViewLayout = null; + _keyboardEvent: ?KeyboardEvent = null; _subscriptions: Array = []; viewRef: {current: React.ElementRef | null, ...}; _initialFrameHeight: number = 0; @@ -91,12 +92,27 @@ class KeyboardAvoidingView extends React.Component { } _onKeyboardChange = (event: ?KeyboardEvent) => { - if (event == null) { + this._keyboardEvent = event; + this._updateBottomIfNecesarry(); + }; + + _onLayout = (event: ViewLayoutEvent) => { + this._frame = event.nativeEvent.layout; + if (!this._initialFrameHeight) { + // save the initial frame height, before the keyboard is visible + this._initialFrameHeight = this._frame.height; + } + + this._updateBottomIfNecesarry(); + }; + + _updateBottomIfNecesarry = () => { + if (this._keyboardEvent == null) { this.setState({bottom: 0}); return; } - const {duration, easing, endCoordinates} = event; + const {duration, easing, endCoordinates} = this._keyboardEvent; const height = this._relativeKeyboardHeight(endCoordinates); if (this.state.bottom === height) { @@ -116,14 +132,6 @@ class KeyboardAvoidingView extends React.Component { this.setState({bottom: height}); }; - _onLayout = (event: ViewLayoutEvent) => { - this._frame = event.nativeEvent.layout; - if (!this._initialFrameHeight) { - // save the initial frame height, before the keyboard is visible - this._initialFrameHeight = this._frame.height; - } - }; - componentDidMount(): void { if (Platform.OS === 'ios') { this._subscriptions = [