diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt index d0ee2ef433871c..99c08fc1ed4681 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<609b55df15ac72da5a3c14dde18a4814>> + * @generated SignedSource<<90dcb658c018c8007953964b24b84278>> */ /** @@ -52,6 +52,12 @@ public object ReactNativeFeatureFlags { @JvmStatic public fun disableMountItemReorderingAndroid(): Boolean = accessor.disableMountItemReorderingAndroid() + /** + * When enabled, Andoid will accumulate updates in rawProps to reduce the number of mounting instructions for cascading rerenders. + */ + @JvmStatic + public fun enableAccumulatedUpdatesInRawPropsAndroid(): Boolean = accessor.enableAccumulatedUpdatesInRawPropsAndroid() + /** * Kill-switch to turn off support for aling-items:baseline on Fabric iOS. */ diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt index 7e87b950dc82cd..b86968cc1e1bbb 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<0be0090ba864cd4fe0bd2c22e419923c>> + * @generated SignedSource<> */ /** @@ -24,6 +24,7 @@ public class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAccesso private var completeReactInstanceCreationOnBgThreadOnAndroidCache: Boolean? = null private var disableEventLoopOnBridgelessCache: Boolean? = null private var disableMountItemReorderingAndroidCache: Boolean? = null + private var enableAccumulatedUpdatesInRawPropsAndroidCache: Boolean? = null private var enableAlignItemsBaselineOnFabricIOSCache: Boolean? = null private var enableAndroidLineHeightCenteringCache: Boolean? = null private var enableBridgelessArchitectureCache: Boolean? = null @@ -104,6 +105,15 @@ public class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAccesso return cached } + override fun enableAccumulatedUpdatesInRawPropsAndroid(): Boolean { + var cached = enableAccumulatedUpdatesInRawPropsAndroidCache + if (cached == null) { + cached = ReactNativeFeatureFlagsCxxInterop.enableAccumulatedUpdatesInRawPropsAndroid() + enableAccumulatedUpdatesInRawPropsAndroidCache = cached + } + return cached + } + override fun enableAlignItemsBaselineOnFabricIOS(): Boolean { var cached = enableAlignItemsBaselineOnFabricIOSCache if (cached == null) { diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt index c92b0c68a33949..4e192bd0280576 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<> + * @generated SignedSource<<2e766bcc58b8d6b0fb605ee71520dd2e>> */ /** @@ -36,6 +36,8 @@ public object ReactNativeFeatureFlagsCxxInterop { @DoNotStrip @JvmStatic public external fun disableMountItemReorderingAndroid(): Boolean + @DoNotStrip @JvmStatic public external fun enableAccumulatedUpdatesInRawPropsAndroid(): Boolean + @DoNotStrip @JvmStatic public external fun enableAlignItemsBaselineOnFabricIOS(): Boolean @DoNotStrip @JvmStatic public external fun enableAndroidLineHeightCentering(): Boolean diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt index f44cdadae12ca2..c9ff39c7eadc97 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<04ac11c085b2880db40d44e431db42f2>> + * @generated SignedSource<> */ /** @@ -31,6 +31,8 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi override fun disableMountItemReorderingAndroid(): Boolean = false + override fun enableAccumulatedUpdatesInRawPropsAndroid(): Boolean = false + override fun enableAlignItemsBaselineOnFabricIOS(): Boolean = true override fun enableAndroidLineHeightCentering(): Boolean = true diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt index 348e334c34fab2..1fc13f5b720ee8 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<0f7a852c7c44b4074bf618252fecb2f6>> + * @generated SignedSource<> */ /** @@ -28,6 +28,7 @@ public class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcces private var completeReactInstanceCreationOnBgThreadOnAndroidCache: Boolean? = null private var disableEventLoopOnBridgelessCache: Boolean? = null private var disableMountItemReorderingAndroidCache: Boolean? = null + private var enableAccumulatedUpdatesInRawPropsAndroidCache: Boolean? = null private var enableAlignItemsBaselineOnFabricIOSCache: Boolean? = null private var enableAndroidLineHeightCenteringCache: Boolean? = null private var enableBridgelessArchitectureCache: Boolean? = null @@ -112,6 +113,16 @@ public class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcces return cached } + override fun enableAccumulatedUpdatesInRawPropsAndroid(): Boolean { + var cached = enableAccumulatedUpdatesInRawPropsAndroidCache + if (cached == null) { + cached = currentProvider.enableAccumulatedUpdatesInRawPropsAndroid() + accessedFeatureFlags.add("enableAccumulatedUpdatesInRawPropsAndroid") + enableAccumulatedUpdatesInRawPropsAndroidCache = cached + } + return cached + } + override fun enableAlignItemsBaselineOnFabricIOS(): Boolean { var cached = enableAlignItemsBaselineOnFabricIOSCache if (cached == null) { diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt index cd32e8b71b55df..8c9de5d42619ae 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<190f00e954f343b076cfe5ef75ee4539>> + * @generated SignedSource<<94d6ce778ccf52a7f7b2ab574b1c9547>> */ /** @@ -31,6 +31,8 @@ public interface ReactNativeFeatureFlagsProvider { @DoNotStrip public fun disableMountItemReorderingAndroid(): Boolean + @DoNotStrip public fun enableAccumulatedUpdatesInRawPropsAndroid(): Boolean + @DoNotStrip public fun enableAlignItemsBaselineOnFabricIOS(): Boolean @DoNotStrip public fun enableAndroidLineHeightCentering(): Boolean 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 f5a1d23cbb38d0..77a235295abfb8 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 @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -215,18 +216,26 @@ inline float scale(Float value, Float pointScaleFactor) { jni::local_ref getProps( const ShadowView& oldShadowView, const ShadowView& newShadowView) { - auto componentName = newShadowView.componentName; // We calculate the diffing between the props of the last mounted ShadowTree // and the Props of the latest commited ShadowTree). ONLY for // components when the "enablePropsUpdateReconciliationAndroid" feature flag // is enabled. + auto* oldProps = oldShadowView.props.get(); + auto* newProps = newShadowView.props.get(); if (ReactNativeFeatureFlags::enablePropsUpdateReconciliationAndroid() && - strcmp(componentName, "View") == 0) { - const Props* oldProps = oldShadowView.props.get(); - auto diffProps = newShadowView.props->getDiffProps(oldProps); - return ReadableNativeMap::newObjectCxxArgs(diffProps); + strcmp(newShadowView.componentName, "View") == 0) { + return ReadableNativeMap::newObjectCxxArgs( + newProps->getDiffProps(oldProps)); } - return ReadableNativeMap::newObjectCxxArgs(newShadowView.props->rawProps); + if (ReactNativeFeatureFlags::enableAccumulatedUpdatesInRawPropsAndroid()) { + if (oldProps == nullptr) { + return ReadableNativeMap::newObjectCxxArgs(newProps->rawProps); + } else { + return ReadableNativeMap::newObjectCxxArgs( + diffDynamicProps(oldProps->rawProps, newProps->rawProps)); + } + } + return ReadableNativeMap::newObjectCxxArgs(newProps->rawProps); } struct InstructionBuffer { @@ -587,13 +596,25 @@ void FabricMountingManager::executeMount( bool shouldCreateView = !allocatedViewTags.contains(newChildShadowView.tag); - if (shouldCreateView) { - LOG(ERROR) << "Emitting insert for unallocated view " - << newChildShadowView.tag; + if (ReactNativeFeatureFlags:: + enableAccumulatedUpdatesInRawPropsAndroid()) { + if (shouldCreateView) { + LOG(ERROR) << "Emitting insert for unallocated view " + << newChildShadowView.tag; + } (maintainMutationOrder ? cppCommonMountItems : cppUpdatePropsMountItems) .push_back(CppMountItem::UpdatePropsMountItem( {}, newChildShadowView)); + } else { + if (shouldCreateView) { + LOG(ERROR) << "Emitting insert for unallocated view " + << newChildShadowView.tag; + (maintainMutationOrder ? cppCommonMountItems + : cppUpdatePropsMountItems) + .push_back(CppMountItem::UpdatePropsMountItem( + {}, newChildShadowView)); + } } // State diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricUIManagerBinding.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricUIManagerBinding.cpp index 80bbbd0805fd38..1c356ca9fc00dd 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricUIManagerBinding.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricUIManagerBinding.cpp @@ -514,60 +514,71 @@ FabricUIManagerBinding::getMountingManager(const char* locationHint) { void FabricUIManagerBinding::schedulerDidFinishTransaction( const std::shared_ptr& mountingCoordinator) { - // We shouldn't be pulling the transaction here (which triggers diffing of - // the trees to determine the mutations to run on the host platform), - // but we have to due to current limitations in the Android implementation. - auto mountingTransaction = mountingCoordinator->pullTransaction( - // Indicate that the transaction will be performed asynchronously - ReactNativeFeatureFlags:: - fixMountingCoordinatorReportedPendingTransactionsOnAndroid()); - if (!mountingTransaction.has_value()) { - return; - } + if (ReactNativeFeatureFlags::enableAccumulatedUpdatesInRawPropsAndroid()) { + // We don't do anything here. We will pull the transaction in + // `schedulerShouldRenderTransactions`. + } else { + // We shouldn't be pulling the transaction here (which triggers diffing of + // the trees to determine the mutations to run on the host platform), + // but we have to due to current limitations in the Android implementation. + auto mountingTransaction = mountingCoordinator->pullTransaction( + // Indicate that the transaction will be performed asynchronously + ReactNativeFeatureFlags:: + fixMountingCoordinatorReportedPendingTransactionsOnAndroid()); + if (!mountingTransaction.has_value()) { + return; + } - std::unique_lock lock(pendingTransactionsMutex_); - auto pendingTransaction = std::find_if( - pendingTransactions_.begin(), - pendingTransactions_.end(), - [&](const auto& transaction) { - return transaction.getSurfaceId() == - mountingTransaction->getSurfaceId(); - }); + std::unique_lock lock(pendingTransactionsMutex_); + auto pendingTransaction = std::find_if( + pendingTransactions_.begin(), + pendingTransactions_.end(), + [&](const auto& transaction) { + return transaction.getSurfaceId() == + mountingTransaction->getSurfaceId(); + }); - if (pendingTransaction != pendingTransactions_.end()) { - pendingTransaction->mergeWith(std::move(*mountingTransaction)); - } else { - pendingTransactions_.push_back(std::move(*mountingTransaction)); + if (pendingTransaction != pendingTransactions_.end()) { + pendingTransaction->mergeWith(std::move(*mountingTransaction)); + } else { + pendingTransactions_.push_back(std::move(*mountingTransaction)); + } } } void FabricUIManagerBinding::schedulerShouldRenderTransactions( - const std::shared_ptr< - const MountingCoordinator>& /* mountingCoordinator */) { + const std::shared_ptr& mountingCoordinator) { auto mountingManager = getMountingManager("schedulerShouldRenderTransactions"); if (!mountingManager) { return; } + if (ReactNativeFeatureFlags::enableAccumulatedUpdatesInRawPropsAndroid()) { + auto mountingTransaction = mountingCoordinator->pullTransaction(); + if (mountingTransaction.has_value()) { + auto transaction = std::move(*mountingTransaction); + mountingManager->executeMount(transaction); + } + } else { + std::vector pendingTransactions; + + { + // Retain the lock to access the pending transactions but not to execute + // the mount operations because that method can call into this method + // again. + // + // This can be re-entrant when mounting manager triggers state updates + // synchronously (this can happen when committing from the UI thread). + // This is safe because we're already combining all the transactions for + // the same surface ID in a single transaction in the pending transactions + // list, so operations won't run out of order. + std::unique_lock lock(pendingTransactionsMutex_); + pendingTransactions_.swap(pendingTransactions); + } - std::vector pendingTransactions; - - { - // Retain the lock to access the pending transactions but not to execute - // the mount operations because that method can call into this method - // again. - // - // This can be re-entrant when mounting manager triggers state updates - // synchronously (this can happen when committing from the UI thread). - // This is safe because we're already combining all the transactions for the - // same surface ID in a single transaction in the pending transactions list, - // so operations won't run out of order. - std::unique_lock lock(pendingTransactionsMutex_); - pendingTransactions_.swap(pendingTransactions); - } - - for (auto& transaction : pendingTransactions) { - mountingManager->executeMount(transaction); + for (auto& transaction : pendingTransactions) { + mountingManager->executeMount(transaction); + } } } diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp index d576fc3d71bf7a..836bcf085d02d8 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<8a9673f2f81917b3466fb955d5641720>> + * @generated SignedSource<<260f2446e2c2d5ad3e4089798bb86ae0>> */ /** @@ -63,6 +63,12 @@ class ReactNativeFeatureFlagsProviderHolder return method(javaProvider_); } + bool enableAccumulatedUpdatesInRawPropsAndroid() override { + static const auto method = + getReactNativeFeatureFlagsProviderJavaClass()->getMethod("enableAccumulatedUpdatesInRawPropsAndroid"); + return method(javaProvider_); + } + bool enableAlignItemsBaselineOnFabricIOS() override { static const auto method = getReactNativeFeatureFlagsProviderJavaClass()->getMethod("enableAlignItemsBaselineOnFabricIOS"); @@ -345,6 +351,11 @@ bool JReactNativeFeatureFlagsCxxInterop::disableMountItemReorderingAndroid( return ReactNativeFeatureFlags::disableMountItemReorderingAndroid(); } +bool JReactNativeFeatureFlagsCxxInterop::enableAccumulatedUpdatesInRawPropsAndroid( + facebook::jni::alias_ref /*unused*/) { + return ReactNativeFeatureFlags::enableAccumulatedUpdatesInRawPropsAndroid(); +} + bool JReactNativeFeatureFlagsCxxInterop::enableAlignItemsBaselineOnFabricIOS( facebook::jni::alias_ref /*unused*/) { return ReactNativeFeatureFlags::enableAlignItemsBaselineOnFabricIOS(); @@ -603,6 +614,9 @@ void JReactNativeFeatureFlagsCxxInterop::registerNatives() { makeNativeMethod( "disableMountItemReorderingAndroid", JReactNativeFeatureFlagsCxxInterop::disableMountItemReorderingAndroid), + makeNativeMethod( + "enableAccumulatedUpdatesInRawPropsAndroid", + JReactNativeFeatureFlagsCxxInterop::enableAccumulatedUpdatesInRawPropsAndroid), makeNativeMethod( "enableAlignItemsBaselineOnFabricIOS", JReactNativeFeatureFlagsCxxInterop::enableAlignItemsBaselineOnFabricIOS), diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h b/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h index df9ef850a5a8f2..5f980e65887d64 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<> + * @generated SignedSource<> */ /** @@ -42,6 +42,9 @@ class JReactNativeFeatureFlagsCxxInterop static bool disableMountItemReorderingAndroid( facebook::jni::alias_ref); + static bool enableAccumulatedUpdatesInRawPropsAndroid( + facebook::jni::alias_ref); + static bool enableAlignItemsBaselineOnFabricIOS( facebook::jni::alias_ref); diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp index 564b1ca5698f79..eda15d27b3710c 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<> + * @generated SignedSource<> */ /** @@ -42,6 +42,10 @@ bool ReactNativeFeatureFlags::disableMountItemReorderingAndroid() { return getAccessor().disableMountItemReorderingAndroid(); } +bool ReactNativeFeatureFlags::enableAccumulatedUpdatesInRawPropsAndroid() { + return getAccessor().enableAccumulatedUpdatesInRawPropsAndroid(); +} + bool ReactNativeFeatureFlags::enableAlignItemsBaselineOnFabricIOS() { return getAccessor().enableAlignItemsBaselineOnFabricIOS(); } diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h index c14b2cff64293e..053603f593e376 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<> + * @generated SignedSource<<4a163a2008d8b4258395784286f6ab18>> */ /** @@ -59,6 +59,11 @@ class ReactNativeFeatureFlags { */ RN_EXPORT static bool disableMountItemReorderingAndroid(); + /** + * When enabled, Andoid will accumulate updates in rawProps to reduce the number of mounting instructions for cascading rerenders. + */ + RN_EXPORT static bool enableAccumulatedUpdatesInRawPropsAndroid(); + /** * Kill-switch to turn off support for aling-items:baseline on Fabric iOS. */ diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp index e2e528c86fe8b7..1d853ec0a2d4e9 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<1cd2586e0118ba4a828fd99fdda97187>> + * @generated SignedSource<<89510eedf1ad7692dabe792b1b9dc6bc>> */ /** @@ -101,6 +101,24 @@ bool ReactNativeFeatureFlagsAccessor::disableMountItemReorderingAndroid() { return flagValue.value(); } +bool ReactNativeFeatureFlagsAccessor::enableAccumulatedUpdatesInRawPropsAndroid() { + auto flagValue = enableAccumulatedUpdatesInRawPropsAndroid_.load(); + + if (!flagValue.has_value()) { + // This block is not exclusive but it is not necessary. + // If multiple threads try to initialize the feature flag, we would only + // be accessing the provider multiple times but the end state of this + // instance and the returned flag value would be the same. + + markFlagAsAccessed(4, "enableAccumulatedUpdatesInRawPropsAndroid"); + + flagValue = currentProvider_->enableAccumulatedUpdatesInRawPropsAndroid(); + enableAccumulatedUpdatesInRawPropsAndroid_ = flagValue; + } + + return flagValue.value(); +} + bool ReactNativeFeatureFlagsAccessor::enableAlignItemsBaselineOnFabricIOS() { auto flagValue = enableAlignItemsBaselineOnFabricIOS_.load(); @@ -110,7 +128,7 @@ bool ReactNativeFeatureFlagsAccessor::enableAlignItemsBaselineOnFabricIOS() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(4, "enableAlignItemsBaselineOnFabricIOS"); + markFlagAsAccessed(5, "enableAlignItemsBaselineOnFabricIOS"); flagValue = currentProvider_->enableAlignItemsBaselineOnFabricIOS(); enableAlignItemsBaselineOnFabricIOS_ = flagValue; @@ -128,7 +146,7 @@ bool ReactNativeFeatureFlagsAccessor::enableAndroidLineHeightCentering() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(5, "enableAndroidLineHeightCentering"); + markFlagAsAccessed(6, "enableAndroidLineHeightCentering"); flagValue = currentProvider_->enableAndroidLineHeightCentering(); enableAndroidLineHeightCentering_ = flagValue; @@ -146,7 +164,7 @@ bool ReactNativeFeatureFlagsAccessor::enableBridgelessArchitecture() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(6, "enableBridgelessArchitecture"); + markFlagAsAccessed(7, "enableBridgelessArchitecture"); flagValue = currentProvider_->enableBridgelessArchitecture(); enableBridgelessArchitecture_ = flagValue; @@ -164,7 +182,7 @@ bool ReactNativeFeatureFlagsAccessor::enableCppPropsIteratorSetter() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(7, "enableCppPropsIteratorSetter"); + markFlagAsAccessed(8, "enableCppPropsIteratorSetter"); flagValue = currentProvider_->enableCppPropsIteratorSetter(); enableCppPropsIteratorSetter_ = flagValue; @@ -182,7 +200,7 @@ bool ReactNativeFeatureFlagsAccessor::enableDeletionOfUnmountedViews() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(8, "enableDeletionOfUnmountedViews"); + markFlagAsAccessed(9, "enableDeletionOfUnmountedViews"); flagValue = currentProvider_->enableDeletionOfUnmountedViews(); enableDeletionOfUnmountedViews_ = flagValue; @@ -200,7 +218,7 @@ bool ReactNativeFeatureFlagsAccessor::enableEagerRootViewAttachment() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(9, "enableEagerRootViewAttachment"); + markFlagAsAccessed(10, "enableEagerRootViewAttachment"); flagValue = currentProvider_->enableEagerRootViewAttachment(); enableEagerRootViewAttachment_ = flagValue; @@ -218,7 +236,7 @@ bool ReactNativeFeatureFlagsAccessor::enableEventEmitterRetentionDuringGesturesO // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(10, "enableEventEmitterRetentionDuringGesturesOnAndroid"); + markFlagAsAccessed(11, "enableEventEmitterRetentionDuringGesturesOnAndroid"); flagValue = currentProvider_->enableEventEmitterRetentionDuringGesturesOnAndroid(); enableEventEmitterRetentionDuringGesturesOnAndroid_ = flagValue; @@ -236,7 +254,7 @@ bool ReactNativeFeatureFlagsAccessor::enableFabricLogs() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(11, "enableFabricLogs"); + markFlagAsAccessed(12, "enableFabricLogs"); flagValue = currentProvider_->enableFabricLogs(); enableFabricLogs_ = flagValue; @@ -254,7 +272,7 @@ bool ReactNativeFeatureFlagsAccessor::enableFabricRenderer() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(12, "enableFabricRenderer"); + markFlagAsAccessed(13, "enableFabricRenderer"); flagValue = currentProvider_->enableFabricRenderer(); enableFabricRenderer_ = flagValue; @@ -272,7 +290,7 @@ bool ReactNativeFeatureFlagsAccessor::enableFixForViewCommandRace() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(13, "enableFixForViewCommandRace"); + markFlagAsAccessed(14, "enableFixForViewCommandRace"); flagValue = currentProvider_->enableFixForViewCommandRace(); enableFixForViewCommandRace_ = flagValue; @@ -290,7 +308,7 @@ bool ReactNativeFeatureFlagsAccessor::enableGranularShadowTreeStateReconciliatio // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(14, "enableGranularShadowTreeStateReconciliation"); + markFlagAsAccessed(15, "enableGranularShadowTreeStateReconciliation"); flagValue = currentProvider_->enableGranularShadowTreeStateReconciliation(); enableGranularShadowTreeStateReconciliation_ = flagValue; @@ -308,7 +326,7 @@ bool ReactNativeFeatureFlagsAccessor::enableIOSViewClipToPaddingBox() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(15, "enableIOSViewClipToPaddingBox"); + markFlagAsAccessed(16, "enableIOSViewClipToPaddingBox"); flagValue = currentProvider_->enableIOSViewClipToPaddingBox(); enableIOSViewClipToPaddingBox_ = flagValue; @@ -326,7 +344,7 @@ bool ReactNativeFeatureFlagsAccessor::enableImagePrefetchingAndroid() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(16, "enableImagePrefetchingAndroid"); + markFlagAsAccessed(17, "enableImagePrefetchingAndroid"); flagValue = currentProvider_->enableImagePrefetchingAndroid(); enableImagePrefetchingAndroid_ = flagValue; @@ -344,7 +362,7 @@ bool ReactNativeFeatureFlagsAccessor::enableLayoutAnimationsOnAndroid() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(17, "enableLayoutAnimationsOnAndroid"); + markFlagAsAccessed(18, "enableLayoutAnimationsOnAndroid"); flagValue = currentProvider_->enableLayoutAnimationsOnAndroid(); enableLayoutAnimationsOnAndroid_ = flagValue; @@ -362,7 +380,7 @@ bool ReactNativeFeatureFlagsAccessor::enableLayoutAnimationsOnIOS() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(18, "enableLayoutAnimationsOnIOS"); + markFlagAsAccessed(19, "enableLayoutAnimationsOnIOS"); flagValue = currentProvider_->enableLayoutAnimationsOnIOS(); enableLayoutAnimationsOnIOS_ = flagValue; @@ -380,7 +398,7 @@ bool ReactNativeFeatureFlagsAccessor::enableLongTaskAPI() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(19, "enableLongTaskAPI"); + markFlagAsAccessed(20, "enableLongTaskAPI"); flagValue = currentProvider_->enableLongTaskAPI(); enableLongTaskAPI_ = flagValue; @@ -398,7 +416,7 @@ bool ReactNativeFeatureFlagsAccessor::enableNewBackgroundAndBorderDrawables() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(20, "enableNewBackgroundAndBorderDrawables"); + markFlagAsAccessed(21, "enableNewBackgroundAndBorderDrawables"); flagValue = currentProvider_->enableNewBackgroundAndBorderDrawables(); enableNewBackgroundAndBorderDrawables_ = flagValue; @@ -416,7 +434,7 @@ bool ReactNativeFeatureFlagsAccessor::enablePreciseSchedulingForPremountItemsOnA // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(21, "enablePreciseSchedulingForPremountItemsOnAndroid"); + markFlagAsAccessed(22, "enablePreciseSchedulingForPremountItemsOnAndroid"); flagValue = currentProvider_->enablePreciseSchedulingForPremountItemsOnAndroid(); enablePreciseSchedulingForPremountItemsOnAndroid_ = flagValue; @@ -434,7 +452,7 @@ bool ReactNativeFeatureFlagsAccessor::enablePropsUpdateReconciliationAndroid() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(22, "enablePropsUpdateReconciliationAndroid"); + markFlagAsAccessed(23, "enablePropsUpdateReconciliationAndroid"); flagValue = currentProvider_->enablePropsUpdateReconciliationAndroid(); enablePropsUpdateReconciliationAndroid_ = flagValue; @@ -452,7 +470,7 @@ bool ReactNativeFeatureFlagsAccessor::enableReportEventPaintTime() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(23, "enableReportEventPaintTime"); + markFlagAsAccessed(24, "enableReportEventPaintTime"); flagValue = currentProvider_->enableReportEventPaintTime(); enableReportEventPaintTime_ = flagValue; @@ -470,7 +488,7 @@ bool ReactNativeFeatureFlagsAccessor::enableSynchronousStateUpdates() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(24, "enableSynchronousStateUpdates"); + markFlagAsAccessed(25, "enableSynchronousStateUpdates"); flagValue = currentProvider_->enableSynchronousStateUpdates(); enableSynchronousStateUpdates_ = flagValue; @@ -488,7 +506,7 @@ bool ReactNativeFeatureFlagsAccessor::enableUIConsistency() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(25, "enableUIConsistency"); + markFlagAsAccessed(26, "enableUIConsistency"); flagValue = currentProvider_->enableUIConsistency(); enableUIConsistency_ = flagValue; @@ -506,7 +524,7 @@ bool ReactNativeFeatureFlagsAccessor::enableViewRecycling() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(26, "enableViewRecycling"); + markFlagAsAccessed(27, "enableViewRecycling"); flagValue = currentProvider_->enableViewRecycling(); enableViewRecycling_ = flagValue; @@ -524,7 +542,7 @@ bool ReactNativeFeatureFlagsAccessor::excludeYogaFromRawProps() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(27, "excludeYogaFromRawProps"); + markFlagAsAccessed(28, "excludeYogaFromRawProps"); flagValue = currentProvider_->excludeYogaFromRawProps(); excludeYogaFromRawProps_ = flagValue; @@ -542,7 +560,7 @@ bool ReactNativeFeatureFlagsAccessor::fixDifferentiatorEmittingUpdatesWithWrongP // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(28, "fixDifferentiatorEmittingUpdatesWithWrongParentTag"); + markFlagAsAccessed(29, "fixDifferentiatorEmittingUpdatesWithWrongParentTag"); flagValue = currentProvider_->fixDifferentiatorEmittingUpdatesWithWrongParentTag(); fixDifferentiatorEmittingUpdatesWithWrongParentTag_ = flagValue; @@ -560,7 +578,7 @@ bool ReactNativeFeatureFlagsAccessor::fixMappingOfEventPrioritiesBetweenFabricAn // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(29, "fixMappingOfEventPrioritiesBetweenFabricAndReact"); + markFlagAsAccessed(30, "fixMappingOfEventPrioritiesBetweenFabricAndReact"); flagValue = currentProvider_->fixMappingOfEventPrioritiesBetweenFabricAndReact(); fixMappingOfEventPrioritiesBetweenFabricAndReact_ = flagValue; @@ -578,7 +596,7 @@ bool ReactNativeFeatureFlagsAccessor::fixMountingCoordinatorReportedPendingTrans // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(30, "fixMountingCoordinatorReportedPendingTransactionsOnAndroid"); + markFlagAsAccessed(31, "fixMountingCoordinatorReportedPendingTransactionsOnAndroid"); flagValue = currentProvider_->fixMountingCoordinatorReportedPendingTransactionsOnAndroid(); fixMountingCoordinatorReportedPendingTransactionsOnAndroid_ = flagValue; @@ -596,7 +614,7 @@ bool ReactNativeFeatureFlagsAccessor::fuseboxEnabledDebug() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(31, "fuseboxEnabledDebug"); + markFlagAsAccessed(32, "fuseboxEnabledDebug"); flagValue = currentProvider_->fuseboxEnabledDebug(); fuseboxEnabledDebug_ = flagValue; @@ -614,7 +632,7 @@ bool ReactNativeFeatureFlagsAccessor::fuseboxEnabledRelease() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(32, "fuseboxEnabledRelease"); + markFlagAsAccessed(33, "fuseboxEnabledRelease"); flagValue = currentProvider_->fuseboxEnabledRelease(); fuseboxEnabledRelease_ = flagValue; @@ -632,7 +650,7 @@ bool ReactNativeFeatureFlagsAccessor::initEagerTurboModulesOnNativeModulesQueueA // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(33, "initEagerTurboModulesOnNativeModulesQueueAndroid"); + markFlagAsAccessed(34, "initEagerTurboModulesOnNativeModulesQueueAndroid"); flagValue = currentProvider_->initEagerTurboModulesOnNativeModulesQueueAndroid(); initEagerTurboModulesOnNativeModulesQueueAndroid_ = flagValue; @@ -650,7 +668,7 @@ bool ReactNativeFeatureFlagsAccessor::lazyAnimationCallbacks() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(34, "lazyAnimationCallbacks"); + markFlagAsAccessed(35, "lazyAnimationCallbacks"); flagValue = currentProvider_->lazyAnimationCallbacks(); lazyAnimationCallbacks_ = flagValue; @@ -668,7 +686,7 @@ bool ReactNativeFeatureFlagsAccessor::loadVectorDrawablesOnImages() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(35, "loadVectorDrawablesOnImages"); + markFlagAsAccessed(36, "loadVectorDrawablesOnImages"); flagValue = currentProvider_->loadVectorDrawablesOnImages(); loadVectorDrawablesOnImages_ = flagValue; @@ -686,7 +704,7 @@ bool ReactNativeFeatureFlagsAccessor::traceTurboModulePromiseRejectionsOnAndroid // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(36, "traceTurboModulePromiseRejectionsOnAndroid"); + markFlagAsAccessed(37, "traceTurboModulePromiseRejectionsOnAndroid"); flagValue = currentProvider_->traceTurboModulePromiseRejectionsOnAndroid(); traceTurboModulePromiseRejectionsOnAndroid_ = flagValue; @@ -704,7 +722,7 @@ bool ReactNativeFeatureFlagsAccessor::useAlwaysAvailableJSErrorHandling() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(37, "useAlwaysAvailableJSErrorHandling"); + markFlagAsAccessed(38, "useAlwaysAvailableJSErrorHandling"); flagValue = currentProvider_->useAlwaysAvailableJSErrorHandling(); useAlwaysAvailableJSErrorHandling_ = flagValue; @@ -722,7 +740,7 @@ bool ReactNativeFeatureFlagsAccessor::useFabricInterop() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(38, "useFabricInterop"); + markFlagAsAccessed(39, "useFabricInterop"); flagValue = currentProvider_->useFabricInterop(); useFabricInterop_ = flagValue; @@ -740,7 +758,7 @@ bool ReactNativeFeatureFlagsAccessor::useImmediateExecutorInAndroidBridgeless() // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(39, "useImmediateExecutorInAndroidBridgeless"); + markFlagAsAccessed(40, "useImmediateExecutorInAndroidBridgeless"); flagValue = currentProvider_->useImmediateExecutorInAndroidBridgeless(); useImmediateExecutorInAndroidBridgeless_ = flagValue; @@ -758,7 +776,7 @@ bool ReactNativeFeatureFlagsAccessor::useNativeViewConfigsInBridgelessMode() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(40, "useNativeViewConfigsInBridgelessMode"); + markFlagAsAccessed(41, "useNativeViewConfigsInBridgelessMode"); flagValue = currentProvider_->useNativeViewConfigsInBridgelessMode(); useNativeViewConfigsInBridgelessMode_ = flagValue; @@ -776,7 +794,7 @@ bool ReactNativeFeatureFlagsAccessor::useOptimisedViewPreallocationOnAndroid() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(41, "useOptimisedViewPreallocationOnAndroid"); + markFlagAsAccessed(42, "useOptimisedViewPreallocationOnAndroid"); flagValue = currentProvider_->useOptimisedViewPreallocationOnAndroid(); useOptimisedViewPreallocationOnAndroid_ = flagValue; @@ -794,7 +812,7 @@ bool ReactNativeFeatureFlagsAccessor::useOptimizedEventBatchingOnAndroid() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(42, "useOptimizedEventBatchingOnAndroid"); + markFlagAsAccessed(43, "useOptimizedEventBatchingOnAndroid"); flagValue = currentProvider_->useOptimizedEventBatchingOnAndroid(); useOptimizedEventBatchingOnAndroid_ = flagValue; @@ -812,7 +830,7 @@ bool ReactNativeFeatureFlagsAccessor::useRawPropsJsiValue() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(43, "useRawPropsJsiValue"); + markFlagAsAccessed(44, "useRawPropsJsiValue"); flagValue = currentProvider_->useRawPropsJsiValue(); useRawPropsJsiValue_ = flagValue; @@ -830,7 +848,7 @@ bool ReactNativeFeatureFlagsAccessor::useRuntimeShadowNodeReferenceUpdate() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(44, "useRuntimeShadowNodeReferenceUpdate"); + markFlagAsAccessed(45, "useRuntimeShadowNodeReferenceUpdate"); flagValue = currentProvider_->useRuntimeShadowNodeReferenceUpdate(); useRuntimeShadowNodeReferenceUpdate_ = flagValue; @@ -848,7 +866,7 @@ bool ReactNativeFeatureFlagsAccessor::useTurboModuleInterop() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(45, "useTurboModuleInterop"); + markFlagAsAccessed(46, "useTurboModuleInterop"); flagValue = currentProvider_->useTurboModuleInterop(); useTurboModuleInterop_ = flagValue; @@ -866,7 +884,7 @@ bool ReactNativeFeatureFlagsAccessor::useTurboModules() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(46, "useTurboModules"); + markFlagAsAccessed(47, "useTurboModules"); flagValue = currentProvider_->useTurboModules(); useTurboModules_ = flagValue; diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h index 5f0177c50ed077..f79304af717593 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<6be37ce8729f305b92161c7263366c7b>> + * @generated SignedSource<<2040d68aed07dd972867c7ab01e2bee8>> */ /** @@ -36,6 +36,7 @@ class ReactNativeFeatureFlagsAccessor { bool completeReactInstanceCreationOnBgThreadOnAndroid(); bool disableEventLoopOnBridgeless(); bool disableMountItemReorderingAndroid(); + bool enableAccumulatedUpdatesInRawPropsAndroid(); bool enableAlignItemsBaselineOnFabricIOS(); bool enableAndroidLineHeightCentering(); bool enableBridgelessArchitecture(); @@ -90,12 +91,13 @@ class ReactNativeFeatureFlagsAccessor { std::unique_ptr currentProvider_; bool wasOverridden_; - std::array, 47> accessedFeatureFlags_; + std::array, 48> accessedFeatureFlags_; std::atomic> commonTestFlag_; std::atomic> completeReactInstanceCreationOnBgThreadOnAndroid_; std::atomic> disableEventLoopOnBridgeless_; std::atomic> disableMountItemReorderingAndroid_; + std::atomic> enableAccumulatedUpdatesInRawPropsAndroid_; std::atomic> enableAlignItemsBaselineOnFabricIOS_; std::atomic> enableAndroidLineHeightCentering_; std::atomic> enableBridgelessArchitecture_; diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h index 4aedd08b058bf1..44a89f83595d26 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<93d8b298331642e4dfc7aa0ebf0978c2>> + * @generated SignedSource<<14f964cf6d43943bdeed783d28c231e0>> */ /** @@ -43,6 +43,10 @@ class ReactNativeFeatureFlagsDefaults : public ReactNativeFeatureFlagsProvider { return false; } + bool enableAccumulatedUpdatesInRawPropsAndroid() override { + return false; + } + bool enableAlignItemsBaselineOnFabricIOS() override { return true; } diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDynamicProvider.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDynamicProvider.h index faa8fea40bde69..4bfe4e7ee51842 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDynamicProvider.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDynamicProvider.h @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<> + * @generated SignedSource<<5183851785d301eed7757a67209ebef2>> */ /** @@ -81,6 +81,15 @@ class ReactNativeFeatureFlagsDynamicProvider : public ReactNativeFeatureFlagsDef return ReactNativeFeatureFlagsDefaults::disableMountItemReorderingAndroid(); } + bool enableAccumulatedUpdatesInRawPropsAndroid() override { + auto value = values_["enableAccumulatedUpdatesInRawPropsAndroid"]; + if (!value.isNull()) { + return value.getBool(); + } + + return ReactNativeFeatureFlagsDefaults::enableAccumulatedUpdatesInRawPropsAndroid(); + } + bool enableAlignItemsBaselineOnFabricIOS() override { auto value = values_["enableAlignItemsBaselineOnFabricIOS"]; if (!value.isNull()) { diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h index 717db8694a0d1f..b3cbd6ac077d71 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<8e43cf80f518df24cf78180c83bdb2cc>> + * @generated SignedSource<<5dd11d05cb305dccf931f81b0be776fb>> */ /** @@ -29,6 +29,7 @@ class ReactNativeFeatureFlagsProvider { virtual bool completeReactInstanceCreationOnBgThreadOnAndroid() = 0; virtual bool disableEventLoopOnBridgeless() = 0; virtual bool disableMountItemReorderingAndroid() = 0; + virtual bool enableAccumulatedUpdatesInRawPropsAndroid() = 0; virtual bool enableAlignItemsBaselineOnFabricIOS() = 0; virtual bool enableAndroidLineHeightCentering() = 0; virtual bool enableBridgelessArchitecture() = 0; diff --git a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp index ffbf68b6208758..dcb0adacf998bf 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp +++ b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<2bc4bcbe92476dd7de97e804a1e20440>> + * @generated SignedSource<> */ /** @@ -64,6 +64,11 @@ bool NativeReactNativeFeatureFlags::disableMountItemReorderingAndroid( return ReactNativeFeatureFlags::disableMountItemReorderingAndroid(); } +bool NativeReactNativeFeatureFlags::enableAccumulatedUpdatesInRawPropsAndroid( + jsi::Runtime& /*runtime*/) { + return ReactNativeFeatureFlags::enableAccumulatedUpdatesInRawPropsAndroid(); +} + bool NativeReactNativeFeatureFlags::enableAlignItemsBaselineOnFabricIOS( jsi::Runtime& /*runtime*/) { return ReactNativeFeatureFlags::enableAlignItemsBaselineOnFabricIOS(); diff --git a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h index 59c72d291119b5..8af67cdf6fbe19 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h +++ b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<21e01d73d525a42650c97107fb7ed7ae>> + * @generated SignedSource<<864803698ff070ce22a4b2f121acbbc0>> */ /** @@ -45,6 +45,8 @@ class NativeReactNativeFeatureFlags bool disableMountItemReorderingAndroid(jsi::Runtime& runtime); + bool enableAccumulatedUpdatesInRawPropsAndroid(jsi::Runtime& runtime); + bool enableAlignItemsBaselineOnFabricIOS(jsi::Runtime& runtime); bool enableAndroidLineHeightCentering(jsi::Runtime& runtime); diff --git a/packages/react-native/ReactCommon/react/renderer/core/DynamicPropsUtilities.cpp b/packages/react-native/ReactCommon/react/renderer/core/DynamicPropsUtilities.cpp index 7ec8b8e2ed336e..2675896d3e3dfa 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/DynamicPropsUtilities.cpp +++ b/packages/react-native/ReactCommon/react/renderer/core/DynamicPropsUtilities.cpp @@ -36,4 +36,30 @@ folly::dynamic mergeDynamicProps( return result; } +folly::dynamic diffDynamicProps( + const folly::dynamic& oldProps, + const folly::dynamic& newProps) { + folly::dynamic result = folly::dynamic::object(); + if (!oldProps.isObject() || !newProps.isObject()) { + return result; + } + for (const auto& oldPair : oldProps.items()) { + const auto& newIterator = newProps.find(oldPair.first); + if (newIterator == newProps.items().end()) { + // Prop removed. + result[oldPair.first] = nullptr; + } else if (oldPair.second != newIterator->second) { + // Prop changed. + result[oldPair.first] = newIterator->second; + } + } + for (const auto& newIterator : newProps.items()) { + if (oldProps.find(newIterator.first) == oldProps.items().end()) { + // Prop added. + result[newIterator.first] = newIterator.second; + } + } + return result; +} + } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/core/DynamicPropsUtilities.h b/packages/react-native/ReactCommon/react/renderer/core/DynamicPropsUtilities.h index d642d8cfdba8c7..1cb063926693b2 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/DynamicPropsUtilities.h +++ b/packages/react-native/ReactCommon/react/renderer/core/DynamicPropsUtilities.h @@ -48,4 +48,8 @@ folly::dynamic mergeDynamicProps( const folly::dynamic& patch, NullValueStrategy nullValueStrategy); +folly::dynamic diffDynamicProps( + const folly::dynamic& oldProps, + const folly::dynamic& newProps); + } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/core/Props.cpp b/packages/react-native/ReactCommon/react/renderer/core/Props.cpp index 811febf1177287..d88ecf3cea04e8 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/Props.cpp +++ b/packages/react-native/ReactCommon/react/renderer/core/Props.cpp @@ -11,6 +11,7 @@ #include #include +#include "DynamicPropsUtilities.h" namespace facebook::react { @@ -32,7 +33,15 @@ void Props::initialize( ? sourceProps.nativeId : convertRawProp(context, rawProps, "nativeID", sourceProps.nativeId, {}); #ifdef ANDROID - this->rawProps = rawProps.toDynamic(filterObjectKeys); + if (ReactNativeFeatureFlags::enableAccumulatedUpdatesInRawPropsAndroid()) { + auto& oldRawProps = sourceProps.rawProps; + auto newRawProps = rawProps.toDynamic(filterObjectKeys); + auto mergedRawProps = mergeDynamicProps( + oldRawProps, newRawProps, NullValueStrategy::Override); + this->rawProps = mergedRawProps; + } else { + this->rawProps = rawProps.toDynamic(filterObjectKeys); + } #endif } diff --git a/packages/react-native/ReactCommon/react/renderer/core/tests/DynamicPropsUtilitiesTest.cpp b/packages/react-native/ReactCommon/react/renderer/core/tests/DynamicPropsUtilitiesTest.cpp index a79767861dda6f..c536866018ac37 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/tests/DynamicPropsUtilitiesTest.cpp +++ b/packages/react-native/ReactCommon/react/renderer/core/tests/DynamicPropsUtilitiesTest.cpp @@ -16,7 +16,7 @@ using namespace facebook::react; `merge_patch` is used for props forwarding on Android to enable Background Executor and will be removed once JNI layer is reimplmeneted. */ -TEST(DynamicPropsUtilitiesTest, handleNestedObjects) { +TEST(DynamicPropsUtilitiesTest, mergeDynamicPropsHandlesNestedObjects) { dynamic map1 = dynamic::object; map1["style"] = dynamic::object("backgroundColor", "red"); @@ -36,7 +36,7 @@ TEST(DynamicPropsUtilitiesTest, handleNestedObjects) { EXPECT_EQ(result["height"], 100); } -TEST(DynamicPropsUtilitiesTest, handleEmptyObject) { +TEST(DynamicPropsUtilitiesTest, mergeDynamicPropsHandlesEmptyObject) { dynamic map1 = dynamic::object; dynamic map2 = dynamic::object; @@ -53,7 +53,7 @@ TEST(DynamicPropsUtilitiesTest, handleEmptyObject) { EXPECT_EQ(result["height"], 100); } -TEST(DynamicPropsUtilitiesTest, handleNullValue) { +TEST(DynamicPropsUtilitiesTest, mergeDynamicPropsHandleNullValue) { dynamic map1 = dynamic::object; map1["height"] = 100; @@ -65,7 +65,9 @@ TEST(DynamicPropsUtilitiesTest, handleNullValue) { EXPECT_TRUE(result["height"].isNull()); } -TEST(DynamicPropsUtilitiesTest, testNullValueStrategyIgnore) { +TEST( + DynamicPropsUtilitiesTest, + mergeDynamicPropsFollowsNullValueStrategyIgnore) { dynamic map1 = dynamic::object; map1["height"] = 100; @@ -78,3 +80,92 @@ TEST(DynamicPropsUtilitiesTest, testNullValueStrategyIgnore) { EXPECT_EQ(result["height"], 101); EXPECT_TRUE(result["width"].isNull()); } + +TEST(DynamicPropsUtilitiesTest, diffDynamicPropsReturnsCorrectDiff) { + dynamic lhs = dynamic::object; + lhs["a"] = 1; + lhs["b"] = "2"; + + dynamic rhs = dynamic::object; + rhs["a"] = 3; + rhs["c"] = true; + + auto result = diffDynamicProps(lhs, rhs); + + EXPECT_TRUE(result.isObject()); + EXPECT_EQ(result.size(), 3); + EXPECT_EQ(result["a"], 3); + EXPECT_EQ(result["b"], nullptr); + EXPECT_EQ(result["c"], true); +} + +TEST(DynamicPropsUtilitiesTest, diffDynamicPropsHandlesInsertions) { + dynamic lhs = dynamic::object; + lhs["a"] = 1; + + dynamic rhs = dynamic::object; + rhs["a"] = 1; + rhs["b"] = 2; + + auto result = diffDynamicProps(lhs, rhs); + + EXPECT_TRUE(result.isObject()); + EXPECT_EQ(result.size(), 1); + EXPECT_EQ(result["b"], 2); +} + +TEST(DynamicPropsUtilitiesTest, diffDynamicPropsHandlesUpdates) { + dynamic lhs = dynamic::object; + lhs["a"] = 1; + lhs["b"] = 2; + + dynamic rhs = dynamic::object; + rhs["a"] = 3; + rhs["b"] = 4; + + auto result = diffDynamicProps(lhs, rhs); + + EXPECT_TRUE(result.isObject()); + EXPECT_EQ(result.size(), 2); + EXPECT_EQ(result["a"], 3); + EXPECT_EQ(result["b"], 4); +} + +TEST(DynamicPropsUtilitiesTest, diffDynamicPropsHandlesDeletions) { + dynamic lhs = dynamic::object; + lhs["a"] = 1; + lhs["b"] = 2; + + dynamic rhs = dynamic::object; + rhs["a"] = 1; + + auto result = diffDynamicProps(lhs, rhs); + + EXPECT_TRUE(result.isObject()); + EXPECT_EQ(result.size(), 1); + EXPECT_EQ(result["b"], nullptr); +} + +TEST( + DynamicPropsUtilitiesTest, + diffDynamicPropsReturnsEmptyObjectForNonObjectLHS) { + dynamic lhs = dynamic::array; + dynamic rhs = dynamic::object; + + auto result = diffDynamicProps(lhs, rhs); + + EXPECT_TRUE(result.isObject()); + EXPECT_EQ(result.size(), 0); +} + +TEST( + DynamicPropsUtilitiesTest, + diffDynamicPropsReturnsEmptyObjectForNonObjectRHS) { + dynamic lhs = dynamic::object; + dynamic rhs = dynamic::array; + + auto result = diffDynamicProps(lhs, rhs); + + EXPECT_TRUE(result.isObject()); + EXPECT_EQ(result.size(), 0); +} diff --git a/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js b/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js index 068c51f119f95d..c9af89e6b4307b 100644 --- a/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js +++ b/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js @@ -85,6 +85,16 @@ const definitions: FeatureFlagDefinitions = { purpose: 'experimentation', }, }, + enableAccumulatedUpdatesInRawPropsAndroid: { + defaultValue: false, + metadata: { + dateAdded: '2024-12-10', + description: + 'When enabled, Andoid will accumulate updates in rawProps to reduce the number of mounting instructions for cascading rerenders.', + expectedReleaseValue: true, + purpose: 'experimentation', + }, + }, enableAlignItemsBaselineOnFabricIOS: { defaultValue: true, metadata: { diff --git a/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js b/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js index 6a44713fb36817..ee3b50d08331f3 100644 --- a/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js +++ b/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<> + * @generated SignedSource<> * @flow strict */ @@ -55,6 +55,7 @@ export type ReactNativeFeatureFlags = $ReadOnly<{ completeReactInstanceCreationOnBgThreadOnAndroid: Getter, disableEventLoopOnBridgeless: Getter, disableMountItemReorderingAndroid: Getter, + enableAccumulatedUpdatesInRawPropsAndroid: Getter, enableAlignItemsBaselineOnFabricIOS: Getter, enableAndroidLineHeightCentering: Getter, enableBridgelessArchitecture: Getter, @@ -205,6 +206,10 @@ export const disableEventLoopOnBridgeless: Getter = createNativeFlagGet * Prevent FabricMountingManager from reordering mountitems, which may lead to invalid state on the UI thread */ export const disableMountItemReorderingAndroid: Getter = createNativeFlagGetter('disableMountItemReorderingAndroid', false); +/** + * When enabled, Andoid will accumulate updates in rawProps to reduce the number of mounting instructions for cascading rerenders. + */ +export const enableAccumulatedUpdatesInRawPropsAndroid: Getter = createNativeFlagGetter('enableAccumulatedUpdatesInRawPropsAndroid', false); /** * Kill-switch to turn off support for aling-items:baseline on Fabric iOS. */ diff --git a/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js b/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js index a34893dcf26c03..8ad0a470e54803 100644 --- a/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js +++ b/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<01d174fa990b1b9cccd8bea4694fc1b4>> + * @generated SignedSource<<386958552a092ac75840bf3202fb0341>> * @flow strict */ @@ -28,6 +28,7 @@ export interface Spec extends TurboModule { +completeReactInstanceCreationOnBgThreadOnAndroid?: () => boolean; +disableEventLoopOnBridgeless?: () => boolean; +disableMountItemReorderingAndroid?: () => boolean; + +enableAccumulatedUpdatesInRawPropsAndroid?: () => boolean; +enableAlignItemsBaselineOnFabricIOS?: () => boolean; +enableAndroidLineHeightCentering?: () => boolean; +enableBridgelessArchitecture?: () => boolean;