From 0061ca6cf47c5124d2ebe708481fb03da9e8e267 Mon Sep 17 00:00:00 2001 From: Dmytro Rykun Date: Thu, 18 Apr 2024 17:24:07 +0100 Subject: [PATCH] Add early return to diffProperties (#28842) ## Summary This PR adds early return to the `diff` function. We don't need to go through all the entries of `nextProps`, process and deep-diff the values if `nextProps` is the same object as `prevProps`. Roughly 6% of all `diffProperties` calls can be skipped. ## How did you test this change? RNTester. --- .../src/ReactNativeAttributePayload.js | 7 +++++++ packages/shared/ReactFeatureFlags.js | 2 ++ .../shared/forks/ReactFeatureFlags.native-fb-dynamic.js | 1 + packages/shared/forks/ReactFeatureFlags.native-fb.js | 1 + packages/shared/forks/ReactFeatureFlags.native-oss.js | 1 + packages/shared/forks/ReactFeatureFlags.test-renderer.js | 1 + .../forks/ReactFeatureFlags.test-renderer.native-fb.js | 1 + .../shared/forks/ReactFeatureFlags.test-renderer.www.js | 1 + packages/shared/forks/ReactFeatureFlags.www.js | 1 + 9 files changed, 16 insertions(+) diff --git a/packages/react-native-renderer/src/ReactNativeAttributePayload.js b/packages/react-native-renderer/src/ReactNativeAttributePayload.js index 68ba068308..0b316ff1ab 100644 --- a/packages/react-native-renderer/src/ReactNativeAttributePayload.js +++ b/packages/react-native-renderer/src/ReactNativeAttributePayload.js @@ -14,6 +14,8 @@ import { } from 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface'; import isArray from 'shared/isArray'; +import {enableEarlyReturnForPropDiffing} from 'shared/ReactFeatureFlags'; + import type {AttributeConfiguration} from './ReactNativeTypes'; const emptyObject = {}; @@ -483,6 +485,11 @@ export function diff( nextProps: Object, validAttributes: AttributeConfiguration, ): null | Object { + if (enableEarlyReturnForPropDiffing) { + if (prevProps === nextProps) { + return null; // no change + } + } return diffProperties( null, // updatePayload prevProps, diff --git a/packages/shared/ReactFeatureFlags.js b/packages/shared/ReactFeatureFlags.js index 02c4abc3a8..cc1061c372 100644 --- a/packages/shared/ReactFeatureFlags.js +++ b/packages/shared/ReactFeatureFlags.js @@ -119,6 +119,8 @@ export const passChildrenWhenCloningPersistedNodes = false; export const enableServerComponentLogs = __EXPERIMENTAL__; +export const enableEarlyReturnForPropDiffing = false; + /** * Enables an expiration time for retry lanes to avoid starvation. */ diff --git a/packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js b/packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js index f024eb4b1c..2a730a71e1 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js +++ b/packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js @@ -20,6 +20,7 @@ export const alwaysThrottleRetries = __VARIANT__; export const consoleManagedByDevToolsDuringStrictMode = __VARIANT__; export const enableAsyncActions = __VARIANT__; +export const enableEarlyReturnForPropDiffing = __VARIANT__; export const enableComponentStackLocations = __VARIANT__; export const enableDeferRootSchedulingToMicrotask = __VARIANT__; export const enableInfiniteRenderLoopDetection = __VARIANT__; diff --git a/packages/shared/forks/ReactFeatureFlags.native-fb.js b/packages/shared/forks/ReactFeatureFlags.native-fb.js index 5c29c8b9a7..a41dbfce43 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-fb.js +++ b/packages/shared/forks/ReactFeatureFlags.native-fb.js @@ -22,6 +22,7 @@ export const { alwaysThrottleRetries, consoleManagedByDevToolsDuringStrictMode, enableAsyncActions, + enableEarlyReturnForPropDiffing, enableComponentStackLocations, enableDeferRootSchedulingToMicrotask, enableInfiniteRenderLoopDetection, diff --git a/packages/shared/forks/ReactFeatureFlags.native-oss.js b/packages/shared/forks/ReactFeatureFlags.native-oss.js index e1064dfa1b..61b7ef2f40 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-oss.js +++ b/packages/shared/forks/ReactFeatureFlags.native-oss.js @@ -101,6 +101,7 @@ export const allowConcurrentByDefault = false; export const enableTransitionTracing = false; export const enableDO_NOT_USE_disableStrictPassiveEffect = false; export const passChildrenWhenCloningPersistedNodes = false; +export const enableEarlyReturnForPropDiffing = false; // Profiling Only export const enableProfilerTimer = __PROFILE__; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.js index b0a0c7f5d5..ba204b9ee0 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.js @@ -76,6 +76,7 @@ export const disableClientCache = true; export const enableServerComponentKeys = true; export const enableServerComponentLogs = true; export const enableInfiniteRenderLoopDetection = false; +export const enableEarlyReturnForPropDiffing = false; // TODO: This must be in sync with the main ReactFeatureFlags file because // the Test Renderer's value must be the same as the one used by the diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js index 40297ad5fa..b1755e2266 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js @@ -87,6 +87,7 @@ export const disableLegacyMode = false; export const disableDOMTestUtils = false; export const disableDefaultPropsExceptForClasses = false; +export const enableEarlyReturnForPropDiffing = false; // Flow magic to verify the exports of this file match the original version. ((((null: any): ExportsType): FeatureFlagsType): ExportsType); diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js index 0aa61e8b9b..6931c771ff 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js @@ -87,6 +87,7 @@ export const disableLegacyMode = false; export const disableDOMTestUtils = false; export const disableDefaultPropsExceptForClasses = false; +export const enableEarlyReturnForPropDiffing = false; // Flow magic to verify the exports of this file match the original version. ((((null: any): ExportsType): FeatureFlagsType): ExportsType); diff --git a/packages/shared/forks/ReactFeatureFlags.www.js b/packages/shared/forks/ReactFeatureFlags.www.js index 82e3b08c7e..dbf30b546c 100644 --- a/packages/shared/forks/ReactFeatureFlags.www.js +++ b/packages/shared/forks/ReactFeatureFlags.www.js @@ -117,6 +117,7 @@ export const disableStringRefs = false; export const disableLegacyMode = __EXPERIMENTAL__; export const disableDOMTestUtils = false; +export const enableEarlyReturnForPropDiffing = false; // Flow magic to verify the exports of this file match the original version. ((((null: any): ExportsType): FeatureFlagsType): ExportsType);