diff --git a/packages/react-native-renderer/src/ReactNativeAttributePayload.js b/packages/react-native-renderer/src/ReactNativeAttributePayload.js index 0b316ff1ab875..f5fc4af494e27 100644 --- a/packages/react-native-renderer/src/ReactNativeAttributePayload.js +++ b/packages/react-native-renderer/src/ReactNativeAttributePayload.js @@ -15,6 +15,7 @@ import { import isArray from 'shared/isArray'; import {enableEarlyReturnForPropDiffing} from 'shared/ReactFeatureFlags'; +import {enableAddPropertiesFastPath} from 'shared/ReactFeatureFlags'; import type {AttributeConfiguration} from './ReactNativeTypes'; @@ -444,6 +445,68 @@ function diffProperties( return updatePayload; } +function fastAddProperties( + updatePayload: null | Object, + nextProps: Object, + validAttributes: AttributeConfiguration, +): null | Object { + let attributeConfig; + let nextProp; + + for (const propKey in nextProps) { + nextProp = nextProps[propKey]; + + if (nextProp === undefined) { + continue; + } + + attributeConfig = validAttributes[propKey]; + + if (attributeConfig === undefined) { + continue; + } + + if (typeof nextProp === 'function') { + nextProp = (true: any); + } + + if (typeof attributeConfig !== 'object') { + if (!updatePayload) { + updatePayload = ({}: {[string]: $FlowFixMe}); + } + updatePayload[propKey] = nextProp; + continue; + } + + if (typeof attributeConfig.process === 'function') { + if (!updatePayload) { + updatePayload = ({}: {[string]: $FlowFixMe}); + } + updatePayload[propKey] = attributeConfig.process(nextProp); + continue; + } + + if (isArray(nextProp)) { + for (let i = 0; i < nextProp.length; i++) { + updatePayload = fastAddProperties( + updatePayload, + nextProp[i], + ((attributeConfig: any): AttributeConfiguration), + ); + } + continue; + } + + updatePayload = fastAddProperties( + updatePayload, + nextProp, + ((attributeConfig: any): AttributeConfiguration), + ); + } + + return updatePayload; +} + /** * addProperties adds all the valid props to the payload after being processed. */ @@ -452,8 +515,11 @@ function addProperties( props: Object, validAttributes: AttributeConfiguration, ): null | Object { - // TODO: Fast path - return diffProperties(updatePayload, emptyObject, props, validAttributes); + if (enableAddPropertiesFastPath) { + return fastAddProperties(updatePayload, props, validAttributes); + } else { + return diffProperties(updatePayload, emptyObject, props, validAttributes); + } } /** diff --git a/packages/shared/ReactFeatureFlags.js b/packages/shared/ReactFeatureFlags.js index bfb48e65df4a1..ff611728ec1a5 100644 --- a/packages/shared/ReactFeatureFlags.js +++ b/packages/shared/ReactFeatureFlags.js @@ -123,6 +123,8 @@ export const enableServerComponentLogs = __EXPERIMENTAL__; export const enableEarlyReturnForPropDiffing = false; +export const enableAddPropertiesFastPath = 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 2a730a71e15cd..be853f93a9009 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js +++ b/packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js @@ -29,3 +29,4 @@ export const enableUnifiedSyncLane = __VARIANT__; export const passChildrenWhenCloningPersistedNodes = __VARIANT__; export const useModernStrictMode = __VARIANT__; export const disableDefaultPropsExceptForClasses = __VARIANT__; +export const enableAddPropertiesFastPath = __VARIANT__; diff --git a/packages/shared/forks/ReactFeatureFlags.native-fb.js b/packages/shared/forks/ReactFeatureFlags.native-fb.js index dd046dc7a4ccb..135e7e1365cd1 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-fb.js +++ b/packages/shared/forks/ReactFeatureFlags.native-fb.js @@ -31,6 +31,7 @@ export const { passChildrenWhenCloningPersistedNodes, useModernStrictMode, disableDefaultPropsExceptForClasses, + enableAddPropertiesFastPath, } = dynamicFlags; // The rest of the flags are static for better dead code elimination. diff --git a/packages/shared/forks/ReactFeatureFlags.native-oss.js b/packages/shared/forks/ReactFeatureFlags.native-oss.js index 243f63b623d72..7d2ef8902465e 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-oss.js +++ b/packages/shared/forks/ReactFeatureFlags.native-oss.js @@ -103,6 +103,7 @@ export const enableDO_NOT_USE_disableStrictPassiveEffect = false; export const passChildrenWhenCloningPersistedNodes = false; export const enableEarlyReturnForPropDiffing = false; export const enableAsyncIterableChildren = false; +export const enableAddPropertiesFastPath = false; export const renameElementSymbol = true; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.js index e80af511bb71b..8e362743b3cb4 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.js @@ -78,6 +78,7 @@ export const enableServerComponentKeys = true; export const enableServerComponentLogs = true; export const enableInfiniteRenderLoopDetection = false; export const enableEarlyReturnForPropDiffing = false; +export const enableAddPropertiesFastPath = false; export const renameElementSymbol = true; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js index 2338dfcc4d557..8aaac9bdabe37 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js @@ -89,6 +89,7 @@ export const disableDOMTestUtils = false; export const disableDefaultPropsExceptForClasses = false; export const enableEarlyReturnForPropDiffing = false; +export const enableAddPropertiesFastPath = false; export const renameElementSymbol = false; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js index dc6fcc3cec8be..43f3d9553bab1 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js @@ -89,6 +89,7 @@ export const disableDOMTestUtils = false; export const disableDefaultPropsExceptForClasses = false; export const enableEarlyReturnForPropDiffing = false; +export const enableAddPropertiesFastPath = false; export const renameElementSymbol = false; diff --git a/packages/shared/forks/ReactFeatureFlags.www-dynamic.js b/packages/shared/forks/ReactFeatureFlags.www-dynamic.js index af5071c47af3b..d0b39d5abf190 100644 --- a/packages/shared/forks/ReactFeatureFlags.www-dynamic.js +++ b/packages/shared/forks/ReactFeatureFlags.www-dynamic.js @@ -31,6 +31,7 @@ export const enableNoCloningMemoCache = __VARIANT__; export const retryLaneExpirationMs = 5000; export const syncLaneExpirationMs = 250; export const transitionLaneExpirationMs = 5000; +export const enableAddPropertiesFastPath = __VARIANT__; // Enable this flag to help with concurrent mode debugging. // It logs information to the console about React scheduling, rendering, and commit phases. diff --git a/packages/shared/forks/ReactFeatureFlags.www.js b/packages/shared/forks/ReactFeatureFlags.www.js index 252571251f55a..dd899e5830236 100644 --- a/packages/shared/forks/ReactFeatureFlags.www.js +++ b/packages/shared/forks/ReactFeatureFlags.www.js @@ -35,6 +35,7 @@ export const { favorSafetyOverHydrationPerf, disableDefaultPropsExceptForClasses, enableNoCloningMemoCache, + enableAddPropertiesFastPath, } = dynamicFeatureFlags; // On WWW, __EXPERIMENTAL__ is used for a new modern build.