From b875b91b9160f31dc6cc60344de5fa50dff774a3 Mon Sep 17 00:00:00 2001 From: Samuel Susla Date: Tue, 3 Sep 2024 08:26:07 -0700 Subject: [PATCH] do not ignore events dispatched during view creation (#46308) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/46308 changelog: [internal] If an event happens before view has event emitter, the event is stored in a [queue](https://github.com/facebook/react-native/blob/main/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.java#L1218) on [ViewState](https://github.com/facebook/react-native/blob/main/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.java#L1206). Once event emitter is assigned, the queue is drained. However, if view dispatches event during view creation in preallocation, the event is dropped. This happens because when view is created, ViewState for the view is not created yet. The implementation of [createViewUnsafe](https://github.com/facebook/react-native/blob/main/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.java#L655) first creates a view (where view creation may trigger events) and only after it creates [ViewState and stores it inside of mTagToViewState](https://github.com/facebook/react-native/blob/main/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.java#L675-L680). This diff fixes it by creating ViewState for a view before view creation. Reviewed By: javache, rubennorte Differential Revision: D62126909 fbshipit-source-id: bec53ea2f926a43a99dc005be257c5dc7985f373 --- .../mounting/SurfaceMountingManager.java | 43 +++++++++---------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.java index feef4f1eb03..b740f211888 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.java @@ -659,25 +659,22 @@ public class SurfaceMountingManager { @Nullable StateWrapper stateWrapper, @Nullable EventEmitterWrapper eventEmitterWrapper, boolean isLayoutable) { - View view = null; - ViewManager viewManager = null; - ReactStylesDiffMap propMap = new ReactStylesDiffMap(props); - if (isLayoutable) { - viewManager = mViewManagerRegistry.get(componentName); - // View Managers are responsible for dealing with inital state and props. - view = - viewManager.createView( - reactTag, mThemedReactContext, propMap, stateWrapper, mJSResponderHandler); - } - - ViewState viewState = new ViewState(reactTag, view, viewManager); + ViewState viewState = new ViewState(reactTag); viewState.mCurrentProps = propMap; viewState.mStateWrapper = stateWrapper; viewState.mEventEmitter = eventEmitterWrapper; - mTagToViewState.put(reactTag, viewState); + + if (isLayoutable) { + ViewManager viewManager = mViewManagerRegistry.get(componentName); + // View Managers are responsible for dealing with inital state and props. + viewState.mView = + viewManager.createView( + reactTag, mThemedReactContext, propMap, stateWrapper, mJSResponderHandler); + viewState.mViewManager = viewManager; + } } public void updateProps(int reactTag, ReadableMap props) { @@ -949,7 +946,7 @@ public class SurfaceMountingManager { if (viewState == null) { // TODO T62717437 - Use a flag to determine that these event emitters belong to virtual nodes // only. - viewState = new ViewState(reactTag, null, null); + viewState = new ViewState(reactTag); mTagToViewState.put(reactTag, viewState); } EventEmitterWrapper previousEventEmitterWrapper = viewState.mEventEmitter; @@ -1204,21 +1201,21 @@ public class SurfaceMountingManager { * #mTagToViewState}, and they should be updated in the same thread. */ private static class ViewState { - @Nullable final View mView; + @Nullable View mView = null; final int mReactTag; final boolean mIsRoot; - @Nullable final ViewManager mViewManager; - @Nullable public ReactStylesDiffMap mCurrentProps = null; - @Nullable public ReadableMap mCurrentLocalData = null; - @Nullable public StateWrapper mStateWrapper = null; - @Nullable public EventEmitterWrapper mEventEmitter = null; + @Nullable ViewManager mViewManager = null; + @Nullable ReactStylesDiffMap mCurrentProps = null; + @Nullable ReadableMap mCurrentLocalData = null; + @Nullable StateWrapper mStateWrapper = null; + @Nullable EventEmitterWrapper mEventEmitter = null; @ThreadConfined(UI) @Nullable - public Queue mPendingEventQueue = null; + Queue mPendingEventQueue = null; - private ViewState(int reactTag, @Nullable View view, @Nullable ViewManager viewManager) { - this(reactTag, view, viewManager, false); + private ViewState(int reactTag) { + this(reactTag, null, null, false); } private ViewState(