From b9470c330be99b7e4efe538f70070fa839ef7ade Mon Sep 17 00:00:00 2001 From: Tomek Zawadzki Date: Fri, 30 Oct 2026 23:45:14 +0100 Subject: [PATCH] Skip the duplicate state and event emitter for views created and inserted in one transaction Co-Authored-By: Claude Opus 5.5 --- .../react/fabric/FabricMountingManager.cpp | 38 +++++++++++++++---- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.cpp index b5f1eb569b2..b0161a9dd63 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.cpp @@ -621,6 +621,15 @@ void FabricMountingManager::executeMount( std::vector cppUpdateOverflowInsetMountItems; std::vector cppUpdateEventEmitterMountItems; + // Views created by this transaction, with the state and event emitter their + // Create item already passes to Java. Their Insert doesn't need to pass them + // again. + struct CreatedView { + const State* state; + const EventEmitter* eventEmitter; + }; + std::unordered_map createdViews; + { std::lock_guard allocatedViewsLock(allocatedViewsMutex_); @@ -660,6 +669,9 @@ void FabricMountingManager::executeMount( if (shouldCreateView) { cppCommonMountItems.push_back( CppMountItem::CreateMountItem(newChildShadowView)); + createdViews[newChildShadowView.tag] = CreatedView{ + .state = newChildShadowView.state.get(), + .eventEmitter = newChildShadowView.eventEmitter.get()}; } else { allocatedView->second.state = AllocatedViewState::Mounted; } @@ -759,6 +771,13 @@ void FabricMountingManager::executeMount( break; } case ShadowViewMutation::Insert: { + auto createdView = createdViews.find(newChildShadowView.tag); + bool createdWithSameState = createdView != createdViews.end() && + createdView->second.state == newChildShadowView.state.get(); + bool createdWithSameEventEmitter = + createdView != createdViews.end() && + createdView->second.eventEmitter == + newChildShadowView.eventEmitter.get(); if (!isVirtual) { // Insert item cppCommonMountItems.push_back( @@ -807,7 +826,7 @@ void FabricMountingManager::executeMount( } // State - if (newChildShadowView.state) { + if (newChildShadowView.state && !createdWithSameState) { (maintainMutationOrder ? cppCommonMountItems : cppUpdateStateMountItems) .push_back( @@ -848,13 +867,16 @@ void FabricMountingManager::executeMount( } // EventEmitter - // On insert we always update the event emitter, as we do not pass - // it in when preallocating views - (maintainMutationOrder ? cppCommonMountItems - : cppUpdateEventEmitterMountItems) - .push_back( - CppMountItem::UpdateEventEmitterMountItem( - mutation.newChildShadowView)); + // On insert we update the event emitter, as we do not pass it in + // when preallocating views. A view created by this transaction + // already got it with its Create item. + if (!createdWithSameEventEmitter) { + (maintainMutationOrder ? cppCommonMountItems + : cppUpdateEventEmitterMountItems) + .push_back( + CppMountItem::UpdateEventEmitterMountItem( + mutation.newChildShadowView)); + } break; }