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
This commit is contained in:
Samuel Susla
2024-09-03 08:26:07 -07:00
committed by Facebook GitHub Bot
parent a1668e37e5
commit b875b91b91
@@ -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<PendingViewEvent> mPendingEventQueue = null;
Queue<PendingViewEvent> 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(