From f446cf6464df2dc3c1f9e2e3ecaf962a59739ca4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20Norte?= Date: Mon, 25 Mar 2024 09:50:21 -0700 Subject: [PATCH] Enable synchronous state update dispatching behind a flag (#43580) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/43580 Changelog: [internal] This introduces a new feature flag to commit state updates synchronously from the UI thread (generally) instead of dispatching them to the JS thread to be processed there. We can do this now because we introduced a UI consistency mechanism in D55024832 to JS would see a consistent revision during the execution of a specific task. Reviewed By: sammy-SC Differential Revision: D55083029 fbshipit-source-id: 8aa84ddaee383f098252fa679cfb07012ba29bf8 --- .../featureflags/ReactNativeFeatureFlags.kt | 8 +++++- .../ReactNativeFeatureFlagsCxxAccessor.kt | 12 +++++++- .../ReactNativeFeatureFlagsCxxInterop.kt | 4 ++- .../ReactNativeFeatureFlagsDefaults.kt | 4 ++- .../ReactNativeFeatureFlagsLocalAccessor.kt | 13 ++++++++- .../ReactNativeFeatureFlagsProvider.kt | 4 ++- .../JReactNativeFeatureFlagsCxxInterop.cpp | 16 ++++++++++- .../JReactNativeFeatureFlagsCxxInterop.h | 5 +++- .../featureflags/ReactNativeFeatureFlags.cpp | 6 +++- .../featureflags/ReactNativeFeatureFlags.h | 7 ++++- .../ReactNativeFeatureFlagsAccessor.cpp | 28 +++++++++++++++---- .../ReactNativeFeatureFlagsAccessor.h | 6 ++-- .../ReactNativeFeatureFlagsDefaults.h | 6 +++- .../ReactNativeFeatureFlagsProvider.h | 3 +- .../NativeReactNativeFeatureFlags.cpp | 7 ++++- .../NativeReactNativeFeatureFlags.h | 4 ++- .../react/renderer/core/CMakeLists.txt | 1 + .../react/renderer/core/EventDispatcher.cpp | 13 +++++++-- .../react/renderer/core/EventDispatcher.h | 5 +++- .../react/renderer/scheduler/Scheduler.cpp | 3 +- .../ReactNativeFeatureFlags.config.js | 5 ++++ .../featureflags/ReactNativeFeatureFlags.js | 7 ++++- .../specs/NativeReactNativeFeatureFlags.js | 3 +- 23 files changed, 142 insertions(+), 28 deletions(-) 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 50eabadaab6..57dc500d336 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<<20c445fde7a1c2607b58b7797346431f>> + * @generated SignedSource<> */ /** @@ -76,6 +76,12 @@ public object ReactNativeFeatureFlags { @JvmStatic public fun enableSpannableBuildingUnification(): Boolean = accessor.enableSpannableBuildingUnification() + /** + * Dispatches state updates synchronously in Fabric (e.g.: updates the scroll position in the shadow tree synchronously from the main thread). + */ + @JvmStatic + public fun enableSynchronousStateUpdates(): Boolean = accessor.enableSynchronousStateUpdates() + /** * Ensures that JavaScript always has a consistent view of the state of the UI (e.g.: commits done in other threads are not immediately propagated to JS during its execution). */ 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 7df37086a8a..d02b7bef8a5 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<<6e973dcdcdfae14c77a6130207333551>> + * @generated SignedSource<<9184044883f829855c2de9db42566287>> */ /** @@ -28,6 +28,7 @@ public class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAccesso private var enableMicrotasksCache: Boolean? = null private var enableMountHooksAndroidCache: Boolean? = null private var enableSpannableBuildingUnificationCache: Boolean? = null + private var enableSynchronousStateUpdatesCache: Boolean? = null private var enableUIConsistencyCache: Boolean? = null private var inspectorEnableCxxInspectorPackagerConnectionCache: Boolean? = null private var inspectorEnableModernCDPRegistryCache: Boolean? = null @@ -105,6 +106,15 @@ public class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAccesso return cached } + override fun enableSynchronousStateUpdates(): Boolean { + var cached = enableSynchronousStateUpdatesCache + if (cached == null) { + cached = ReactNativeFeatureFlagsCxxInterop.enableSynchronousStateUpdates() + enableSynchronousStateUpdatesCache = cached + } + return cached + } + override fun enableUIConsistency(): Boolean { var cached = enableUIConsistencyCache 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 465c71cf32c..155338b4f95 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<<0d34567fc05555ae401e7f5180dc8771>> + * @generated SignedSource<<4154c0f81f2e5ad7ff03e252c4aa965c>> */ /** @@ -44,6 +44,8 @@ public object ReactNativeFeatureFlagsCxxInterop { @DoNotStrip @JvmStatic public external fun enableSpannableBuildingUnification(): Boolean + @DoNotStrip @JvmStatic public external fun enableSynchronousStateUpdates(): Boolean + @DoNotStrip @JvmStatic public external fun enableUIConsistency(): Boolean @DoNotStrip @JvmStatic public external fun inspectorEnableCxxInspectorPackagerConnection(): 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 1e0f7a392d8..5931f315b79 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<> + * @generated SignedSource<> */ /** @@ -39,6 +39,8 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi override fun enableSpannableBuildingUnification(): Boolean = false + override fun enableSynchronousStateUpdates(): Boolean = false + override fun enableUIConsistency(): Boolean = false override fun inspectorEnableCxxInspectorPackagerConnection(): Boolean = false 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 698251ab09d..bd486e40c1e 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<<8908de9b9d0186f1916d8b55d5854cb2>> + * @generated SignedSource<> */ /** @@ -32,6 +32,7 @@ public class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcces private var enableMicrotasksCache: Boolean? = null private var enableMountHooksAndroidCache: Boolean? = null private var enableSpannableBuildingUnificationCache: Boolean? = null + private var enableSynchronousStateUpdatesCache: Boolean? = null private var enableUIConsistencyCache: Boolean? = null private var inspectorEnableCxxInspectorPackagerConnectionCache: Boolean? = null private var inspectorEnableModernCDPRegistryCache: Boolean? = null @@ -117,6 +118,16 @@ public class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcces return cached } + override fun enableSynchronousStateUpdates(): Boolean { + var cached = enableSynchronousStateUpdatesCache + if (cached == null) { + cached = currentProvider.enableSynchronousStateUpdates() + accessedFeatureFlags.add("enableSynchronousStateUpdates") + enableSynchronousStateUpdatesCache = cached + } + return cached + } + override fun enableUIConsistency(): Boolean { var cached = enableUIConsistencyCache 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 1bd4b3ad6a4..195b7e7b096 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<<7555a704535615fcea44c1261095419a>> + * @generated SignedSource<> */ /** @@ -39,6 +39,8 @@ public interface ReactNativeFeatureFlagsProvider { @DoNotStrip public fun enableSpannableBuildingUnification(): Boolean + @DoNotStrip public fun enableSynchronousStateUpdates(): Boolean + @DoNotStrip public fun enableUIConsistency(): Boolean @DoNotStrip public fun inspectorEnableCxxInspectorPackagerConnection(): Boolean 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 d24467eb205..a34874f06bd 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<> + * @generated SignedSource<> */ /** @@ -87,6 +87,12 @@ class ReactNativeFeatureFlagsProviderHolder return method(javaProvider_); } + bool enableSynchronousStateUpdates() override { + static const auto method = + getReactNativeFeatureFlagsProviderJavaClass()->getMethod("enableSynchronousStateUpdates"); + return method(javaProvider_); + } + bool enableUIConsistency() override { static const auto method = getReactNativeFeatureFlagsProviderJavaClass()->getMethod("enableUIConsistency"); @@ -155,6 +161,11 @@ bool JReactNativeFeatureFlagsCxxInterop::enableSpannableBuildingUnification( return ReactNativeFeatureFlags::enableSpannableBuildingUnification(); } +bool JReactNativeFeatureFlagsCxxInterop::enableSynchronousStateUpdates( + facebook::jni::alias_ref /*unused*/) { + return ReactNativeFeatureFlags::enableSynchronousStateUpdates(); +} + bool JReactNativeFeatureFlagsCxxInterop::enableUIConsistency( facebook::jni::alias_ref /*unused*/) { return ReactNativeFeatureFlags::enableUIConsistency(); @@ -216,6 +227,9 @@ void JReactNativeFeatureFlagsCxxInterop::registerNatives() { makeNativeMethod( "enableSpannableBuildingUnification", JReactNativeFeatureFlagsCxxInterop::enableSpannableBuildingUnification), + makeNativeMethod( + "enableSynchronousStateUpdates", + JReactNativeFeatureFlagsCxxInterop::enableSynchronousStateUpdates), makeNativeMethod( "enableUIConsistency", JReactNativeFeatureFlagsCxxInterop::enableUIConsistency), 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 27e41e73a4e..bc4e40765d1 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<<6b33129341a4b68cdbbdbce9f57e4d63>> */ /** @@ -54,6 +54,9 @@ class JReactNativeFeatureFlagsCxxInterop static bool enableSpannableBuildingUnification( facebook::jni::alias_ref); + static bool enableSynchronousStateUpdates( + facebook::jni::alias_ref); + static bool enableUIConsistency( 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 2a4c352c5a4..b960e7889c2 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<<56f79a4cb62a993f9c3a8ea01eed2ab6>> */ /** @@ -53,6 +53,10 @@ bool ReactNativeFeatureFlags::enableSpannableBuildingUnification() { return getAccessor().enableSpannableBuildingUnification(); } +bool ReactNativeFeatureFlags::enableSynchronousStateUpdates() { + return getAccessor().enableSynchronousStateUpdates(); +} + bool ReactNativeFeatureFlags::enableUIConsistency() { return getAccessor().enableUIConsistency(); } diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h index 0354f83b547..15c05e75435 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<> */ /** @@ -77,6 +77,11 @@ class ReactNativeFeatureFlags { */ RN_EXPORT static bool enableSpannableBuildingUnification(); + /** + * Dispatches state updates synchronously in Fabric (e.g.: updates the scroll position in the shadow tree synchronously from the main thread). + */ + RN_EXPORT static bool enableSynchronousStateUpdates(); + /** * Ensures that JavaScript always has a consistent view of the state of the UI (e.g.: commits done in other threads are not immediately propagated to JS during its execution). */ diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp index f7a4feb4dbb..3310842f48f 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<<2ff39fd4c8330ddca994fc40cdeaaf4c>> + * @generated SignedSource<<5b42b33319369b7936662a2608794ba5>> */ /** @@ -173,6 +173,24 @@ bool ReactNativeFeatureFlagsAccessor::enableSpannableBuildingUnification() { return flagValue.value(); } +bool ReactNativeFeatureFlagsAccessor::enableSynchronousStateUpdates() { + auto flagValue = enableSynchronousStateUpdates_.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(8, "enableSynchronousStateUpdates"); + + flagValue = currentProvider_->enableSynchronousStateUpdates(); + enableSynchronousStateUpdates_ = flagValue; + } + + return flagValue.value(); +} + bool ReactNativeFeatureFlagsAccessor::enableUIConsistency() { auto flagValue = enableUIConsistency_.load(); @@ -182,7 +200,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(8, "enableUIConsistency"); + markFlagAsAccessed(9, "enableUIConsistency"); flagValue = currentProvider_->enableUIConsistency(); enableUIConsistency_ = flagValue; @@ -200,7 +218,7 @@ bool ReactNativeFeatureFlagsAccessor::inspectorEnableCxxInspectorPackagerConnect // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(9, "inspectorEnableCxxInspectorPackagerConnection"); + markFlagAsAccessed(10, "inspectorEnableCxxInspectorPackagerConnection"); flagValue = currentProvider_->inspectorEnableCxxInspectorPackagerConnection(); inspectorEnableCxxInspectorPackagerConnection_ = flagValue; @@ -218,7 +236,7 @@ bool ReactNativeFeatureFlagsAccessor::inspectorEnableModernCDPRegistry() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(10, "inspectorEnableModernCDPRegistry"); + markFlagAsAccessed(11, "inspectorEnableModernCDPRegistry"); flagValue = currentProvider_->inspectorEnableModernCDPRegistry(); inspectorEnableModernCDPRegistry_ = flagValue; @@ -236,7 +254,7 @@ bool ReactNativeFeatureFlagsAccessor::useModernRuntimeScheduler() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(11, "useModernRuntimeScheduler"); + markFlagAsAccessed(12, "useModernRuntimeScheduler"); flagValue = currentProvider_->useModernRuntimeScheduler(); useModernRuntimeScheduler_ = flagValue; diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h index dc3b1f0b99c..9591c3fc030 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<> + * @generated SignedSource<> */ /** @@ -39,6 +39,7 @@ class ReactNativeFeatureFlagsAccessor { bool enableMicrotasks(); bool enableMountHooksAndroid(); bool enableSpannableBuildingUnification(); + bool enableSynchronousStateUpdates(); bool enableUIConsistency(); bool inspectorEnableCxxInspectorPackagerConnection(); bool inspectorEnableModernCDPRegistry(); @@ -53,7 +54,7 @@ class ReactNativeFeatureFlagsAccessor { std::unique_ptr currentProvider_; bool wasOverridden_; - std::array, 12> accessedFeatureFlags_; + std::array, 13> accessedFeatureFlags_; std::atomic> commonTestFlag_; std::atomic> batchRenderingUpdatesInEventLoop_; @@ -63,6 +64,7 @@ class ReactNativeFeatureFlagsAccessor { std::atomic> enableMicrotasks_; std::atomic> enableMountHooksAndroid_; std::atomic> enableSpannableBuildingUnification_; + std::atomic> enableSynchronousStateUpdates_; std::atomic> enableUIConsistency_; std::atomic> inspectorEnableCxxInspectorPackagerConnection_; std::atomic> inspectorEnableModernCDPRegistry_; diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h index 0115a835c63..b9ff005fd37 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<<1450d89abc68821fb348574016874719>> + * @generated SignedSource<<9fd009411ce19224a3102d2713b0b042>> */ /** @@ -59,6 +59,10 @@ class ReactNativeFeatureFlagsDefaults : public ReactNativeFeatureFlagsProvider { return false; } + bool enableSynchronousStateUpdates() override { + return false; + } + bool enableUIConsistency() override { return false; } diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h index cbf80cf641e..21c6cfb65ef 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<> + * @generated SignedSource<<7384eeb8615a45b79cdcceb731d98e9d>> */ /** @@ -33,6 +33,7 @@ class ReactNativeFeatureFlagsProvider { virtual bool enableMicrotasks() = 0; virtual bool enableMountHooksAndroid() = 0; virtual bool enableSpannableBuildingUnification() = 0; + virtual bool enableSynchronousStateUpdates() = 0; virtual bool enableUIConsistency() = 0; virtual bool inspectorEnableCxxInspectorPackagerConnection() = 0; virtual bool inspectorEnableModernCDPRegistry() = 0; diff --git a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp index 8a957343c12..195a87f9bce 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<<7e09a7ad1d178850bdcf73da3eb5623b>> + * @generated SignedSource<<08ed8c4c27411ba5a04acb314eb36b63>> */ /** @@ -77,6 +77,11 @@ bool NativeReactNativeFeatureFlags::enableSpannableBuildingUnification( return ReactNativeFeatureFlags::enableSpannableBuildingUnification(); } +bool NativeReactNativeFeatureFlags::enableSynchronousStateUpdates( + jsi::Runtime& /*runtime*/) { + return ReactNativeFeatureFlags::enableSynchronousStateUpdates(); +} + bool NativeReactNativeFeatureFlags::enableUIConsistency( jsi::Runtime& /*runtime*/) { return ReactNativeFeatureFlags::enableUIConsistency(); diff --git a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h index bdc52a818d5..55a2530553f 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<> + * @generated SignedSource<> */ /** @@ -51,6 +51,8 @@ class NativeReactNativeFeatureFlags bool enableSpannableBuildingUnification(jsi::Runtime& runtime); + bool enableSynchronousStateUpdates(jsi::Runtime& runtime); + bool enableUIConsistency(jsi::Runtime& runtime); bool inspectorEnableCxxInspectorPackagerConnection(jsi::Runtime& runtime); diff --git a/packages/react-native/ReactCommon/react/renderer/core/CMakeLists.txt b/packages/react-native/ReactCommon/react/renderer/core/CMakeLists.txt index 8ffaf81af56..4a2f93bfb38 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/CMakeLists.txt +++ b/packages/react-native/ReactCommon/react/renderer/core/CMakeLists.txt @@ -25,6 +25,7 @@ target_link_libraries(react_render_core logger react_config react_debug + react_featureflags react_render_debug react_render_graphics react_render_mapbuffer diff --git a/packages/react-native/ReactCommon/react/renderer/core/EventDispatcher.cpp b/packages/react-native/ReactCommon/react/renderer/core/EventDispatcher.cpp index 693e6820811..2c8175dc0aa 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/EventDispatcher.cpp +++ b/packages/react-native/ReactCommon/react/renderer/core/EventDispatcher.cpp @@ -7,6 +7,7 @@ #include "EventDispatcher.h" #include +#include #include #include "EventLogger.h" @@ -19,11 +20,13 @@ EventDispatcher::EventDispatcher( const EventQueueProcessor& eventProcessor, const EventBeat::Factory& asynchronousEventBeatFactory, const EventBeat::SharedOwnerBox& ownerBox, - RuntimeScheduler& runtimeScheduler) + RuntimeScheduler& runtimeScheduler, + StatePipe statePipe) : eventQueue_(EventQueue( eventProcessor, asynchronousEventBeatFactory(ownerBox), - runtimeScheduler)) {} + runtimeScheduler)), + statePipe_(std::move(statePipe)) {} void EventDispatcher::dispatchEvent(RawEvent&& rawEvent) const { // Allows the event listener to interrupt default event dispatch @@ -43,7 +46,11 @@ void EventDispatcher::experimental_flushSync() const { } void EventDispatcher::dispatchStateUpdate(StateUpdate&& stateUpdate) const { - eventQueue_.enqueueStateUpdate(std::move(stateUpdate)); + if (ReactNativeFeatureFlags::enableSynchronousStateUpdates()) { + statePipe_(stateUpdate); + } else { + eventQueue_.enqueueStateUpdate(std::move(stateUpdate)); + } } void EventDispatcher::dispatchUniqueEvent(RawEvent&& rawEvent) const { diff --git a/packages/react-native/ReactCommon/react/renderer/core/EventDispatcher.h b/packages/react-native/ReactCommon/react/renderer/core/EventDispatcher.h index b974e5e6ea0..d0331166cef 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/EventDispatcher.h +++ b/packages/react-native/ReactCommon/react/renderer/core/EventDispatcher.h @@ -11,6 +11,7 @@ #include #include #include +#include #include namespace facebook::react { @@ -31,7 +32,8 @@ class EventDispatcher { const EventQueueProcessor& eventProcessor, const EventBeat::Factory& asynchronousEventBeatFactory, const EventBeat::SharedOwnerBox& ownerBox, - RuntimeScheduler& runtimeScheduler); + RuntimeScheduler& runtimeScheduler, + StatePipe statePipe); /* * Dispatches a raw event with given priority using event-delivery pipe. @@ -69,6 +71,7 @@ class EventDispatcher { private: EventQueue eventQueue_; + const StatePipe statePipe_; mutable EventListenerContainer eventListeners_; }; diff --git a/packages/react-native/ReactCommon/react/renderer/scheduler/Scheduler.cpp b/packages/react-native/ReactCommon/react/renderer/scheduler/Scheduler.cpp index 9f5dc0e75f4..7a34d992dcd 100644 --- a/packages/react-native/ReactCommon/react/renderer/scheduler/Scheduler.cpp +++ b/packages/react-native/ReactCommon/react/renderer/scheduler/Scheduler.cpp @@ -91,7 +91,8 @@ Scheduler::Scheduler( EventQueueProcessor(eventPipe, eventPipeConclusion, statePipe), schedulerToolbox.asynchronousEventBeatFactory, eventOwnerBox, - *runtimeScheduler); + *runtimeScheduler, + statePipe); // Casting to `std::shared_ptr`. auto eventDispatcher = diff --git a/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js b/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js index 91e3dd69c8f..396d3290700 100644 --- a/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js +++ b/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js @@ -67,6 +67,11 @@ const definitions: FeatureFlagDefinitions = { description: 'Uses new, deduplicated logic for constructing Android Spannables from text fragments', }, + enableSynchronousStateUpdates: { + defaultValue: false, + description: + 'Dispatches state updates synchronously in Fabric (e.g.: updates the scroll position in the shadow tree synchronously from the main thread).', + }, enableUIConsistency: { defaultValue: false, description: diff --git a/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js b/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js index dffe28a86f1..2e642c0017e 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<<366b36d877532c93aa6e5a97b85edd06>> * @flow strict-local */ @@ -48,6 +48,7 @@ export type ReactNativeFeatureFlags = { enableMicrotasks: Getter, enableMountHooksAndroid: Getter, enableSpannableBuildingUnification: Getter, + enableSynchronousStateUpdates: Getter, enableUIConsistency: Getter, inspectorEnableCxxInspectorPackagerConnection: Getter, inspectorEnableModernCDPRegistry: Getter, @@ -126,6 +127,10 @@ export const enableMountHooksAndroid: Getter = createNativeFlagGetter(' * Uses new, deduplicated logic for constructing Android Spannables from text fragments */ export const enableSpannableBuildingUnification: Getter = createNativeFlagGetter('enableSpannableBuildingUnification', false); +/** + * Dispatches state updates synchronously in Fabric (e.g.: updates the scroll position in the shadow tree synchronously from the main thread). + */ +export const enableSynchronousStateUpdates: Getter = createNativeFlagGetter('enableSynchronousStateUpdates', false); /** * Ensures that JavaScript always has a consistent view of the state of the UI (e.g.: commits done in other threads are not immediately propagated to JS during its execution). */ diff --git a/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js b/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js index ac17e38ee02..227f49d7cfa 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<<2f4c06a0e456d55a4bbd6b8c48c7f22d>> + * @generated SignedSource<<0d744f7a8519800a42cb0c3957862775>> * @flow strict-local */ @@ -31,6 +31,7 @@ export interface Spec extends TurboModule { +enableMicrotasks?: () => boolean; +enableMountHooksAndroid?: () => boolean; +enableSpannableBuildingUnification?: () => boolean; + +enableSynchronousStateUpdates?: () => boolean; +enableUIConsistency?: () => boolean; +inspectorEnableCxxInspectorPackagerConnection?: () => boolean; +inspectorEnableModernCDPRegistry?: () => boolean;