Skip to content

Commit 73bcdfb

Browse files
authored
Introduce a faster version of the addProperties function (#28969)
## Summary This PR introduces a faster version of the `addProperties` function. This new function is basically the `diffProperties` with `prevProps` set to `null`, propagated constants, and all the unreachable code paths collapsed. ## How did you test this change? I've tested this change with [the benchmark app](https://github.com/react-native-community/RNNewArchitectureApp/tree/new-architecture-benchmarks) and got ~4.4% improvement in the view creation time.
1 parent c7b1ae5 commit 73bcdfb

10 files changed

+78
-2
lines changed

packages/react-native-renderer/src/ReactNativeAttributePayload.js

+68-2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
import isArray from 'shared/isArray';
1616

1717
import {enableEarlyReturnForPropDiffing} from 'shared/ReactFeatureFlags';
18+
import {enableAddPropertiesFastPath} from 'shared/ReactFeatureFlags';
1819

1920
import type {AttributeConfiguration} from './ReactNativeTypes';
2021

@@ -444,6 +445,68 @@ function diffProperties(
444445
return updatePayload;
445446
}
446447

448+
function fastAddProperties(
449+
updatePayload: null | Object,
450+
nextProps: Object,
451+
validAttributes: AttributeConfiguration,
452+
): null | Object {
453+
let attributeConfig;
454+
let nextProp;
455+
456+
for (const propKey in nextProps) {
457+
nextProp = nextProps[propKey];
458+
459+
if (nextProp === undefined) {
460+
continue;
461+
}
462+
463+
attributeConfig = validAttributes[propKey];
464+
465+
if (attributeConfig === undefined) {
466+
continue;
467+
}
468+
469+
if (typeof nextProp === 'function') {
470+
nextProp = (true: any);
471+
}
472+
473+
if (typeof attributeConfig !== 'object') {
474+
if (!updatePayload) {
475+
updatePayload = ({}: {[string]: $FlowFixMe});
476+
}
477+
updatePayload[propKey] = nextProp;
478+
continue;
479+
}
480+
481+
if (typeof attributeConfig.process === 'function') {
482+
if (!updatePayload) {
483+
updatePayload = ({}: {[string]: $FlowFixMe});
484+
}
485+
updatePayload[propKey] = attributeConfig.process(nextProp);
486+
continue;
487+
}
488+
489+
if (isArray(nextProp)) {
490+
for (let i = 0; i < nextProp.length; i++) {
491+
updatePayload = fastAddProperties(
492+
updatePayload,
493+
nextProp[i],
494+
((attributeConfig: any): AttributeConfiguration),
495+
);
496+
}
497+
continue;
498+
}
499+
500+
updatePayload = fastAddProperties(
501+
updatePayload,
502+
nextProp,
503+
((attributeConfig: any): AttributeConfiguration),
504+
);
505+
}
506+
507+
return updatePayload;
508+
}
509+
447510
/**
448511
* addProperties adds all the valid props to the payload after being processed.
449512
*/
@@ -452,8 +515,11 @@ function addProperties(
452515
props: Object,
453516
validAttributes: AttributeConfiguration,
454517
): null | Object {
455-
// TODO: Fast path
456-
return diffProperties(updatePayload, emptyObject, props, validAttributes);
518+
if (enableAddPropertiesFastPath) {
519+
return fastAddProperties(updatePayload, props, validAttributes);
520+
} else {
521+
return diffProperties(updatePayload, emptyObject, props, validAttributes);
522+
}
457523
}
458524

459525
/**

packages/shared/ReactFeatureFlags.js

+2
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,8 @@ export const enableServerComponentLogs = __EXPERIMENTAL__;
123123

124124
export const enableEarlyReturnForPropDiffing = false;
125125

126+
export const enableAddPropertiesFastPath = false;
127+
126128
/**
127129
* Enables an expiration time for retry lanes to avoid starvation.
128130
*/

packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js

+1
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,4 @@ export const enableUnifiedSyncLane = __VARIANT__;
2929
export const passChildrenWhenCloningPersistedNodes = __VARIANT__;
3030
export const useModernStrictMode = __VARIANT__;
3131
export const disableDefaultPropsExceptForClasses = __VARIANT__;
32+
export const enableAddPropertiesFastPath = __VARIANT__;

packages/shared/forks/ReactFeatureFlags.native-fb.js

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export const {
3131
passChildrenWhenCloningPersistedNodes,
3232
useModernStrictMode,
3333
disableDefaultPropsExceptForClasses,
34+
enableAddPropertiesFastPath,
3435
} = dynamicFlags;
3536

3637
// The rest of the flags are static for better dead code elimination.

packages/shared/forks/ReactFeatureFlags.native-oss.js

+1
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ export const enableDO_NOT_USE_disableStrictPassiveEffect = false;
103103
export const passChildrenWhenCloningPersistedNodes = false;
104104
export const enableEarlyReturnForPropDiffing = false;
105105
export const enableAsyncIterableChildren = false;
106+
export const enableAddPropertiesFastPath = false;
106107

107108
export const renameElementSymbol = true;
108109

packages/shared/forks/ReactFeatureFlags.test-renderer.js

+1
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ export const enableServerComponentKeys = true;
7878
export const enableServerComponentLogs = true;
7979
export const enableInfiniteRenderLoopDetection = false;
8080
export const enableEarlyReturnForPropDiffing = false;
81+
export const enableAddPropertiesFastPath = false;
8182

8283
export const renameElementSymbol = true;
8384

packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js

+1
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ export const disableDOMTestUtils = false;
8989

9090
export const disableDefaultPropsExceptForClasses = false;
9191
export const enableEarlyReturnForPropDiffing = false;
92+
export const enableAddPropertiesFastPath = false;
9293

9394
export const renameElementSymbol = false;
9495

packages/shared/forks/ReactFeatureFlags.test-renderer.www.js

+1
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ export const disableDOMTestUtils = false;
8989

9090
export const disableDefaultPropsExceptForClasses = false;
9191
export const enableEarlyReturnForPropDiffing = false;
92+
export const enableAddPropertiesFastPath = false;
9293

9394
export const renameElementSymbol = false;
9495

packages/shared/forks/ReactFeatureFlags.www-dynamic.js

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export const enableNoCloningMemoCache = __VARIANT__;
3131
export const retryLaneExpirationMs = 5000;
3232
export const syncLaneExpirationMs = 250;
3333
export const transitionLaneExpirationMs = 5000;
34+
export const enableAddPropertiesFastPath = __VARIANT__;
3435

3536
// Enable this flag to help with concurrent mode debugging.
3637
// It logs information to the console about React scheduling, rendering, and commit phases.

packages/shared/forks/ReactFeatureFlags.www.js

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ export const {
3535
favorSafetyOverHydrationPerf,
3636
disableDefaultPropsExceptForClasses,
3737
enableNoCloningMemoCache,
38+
enableAddPropertiesFastPath,
3839
} = dynamicFeatureFlags;
3940

4041
// On WWW, __EXPERIMENTAL__ is used for a new modern build.

0 commit comments

Comments
 (0)