@samitouri / QOS-React-1 / commits / 8b55eb4e72

Cleanup props diffing experiments (#33381)

## Summary We completed testing on these internally, so can cleanup the separate fast and slow paths and remove the `enableShallowPropDiffing` flag which we're not pursuing. ## How did you test this change? ``` yarn test ReactNativeAttributePayloadFabric ```

Pieter De Baets committed May 30, 2025 at 17:17 UTC 8b55eb4e724271206bd5dec7dba0a35aedc74493
10 files changed +11 -85
packages/react-native-renderer/src/ReactNativeAttributePayloadFabric.js
+11 -64
@@ -14,11 +14,6 @@ import {
14 } from 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface';
15 import isArray from 'shared/isArray';
16
17 -import {
18 - enableShallowPropDiffing,
19 - enableFastAddPropertiesInDiffing,
20 -} from 'shared/ReactFeatureFlags';
21 -
17 import type {AttributeConfiguration} from './ReactNativeTypes';
18
19 const emptyObject = {};
@@ -141,12 +136,12 @@ function diffNestedArrayProperty(
136 );
137 }
138 for (; i < nextArray.length; i++) {
144 - // Add all remaining properties.
145 - updatePayload = addNestedProperty(
146 - updatePayload,
147 - nextArray[i],
148 - validAttributes,
149 - );
139 + // Add all remaining properties
140 + const nextProp = nextArray[i];
141 + if (!nextProp) {
142 + continue;
143 + }
144 + updatePayload = addNestedProperty(updatePayload, nextProp, validAttributes);
145 }
146 return updatePayload;
147 }
@@ -205,41 +200,6 @@ function diffNestedProperty(
200 );
201 }
202
208 -/**
209 - * addNestedProperty takes a single set of props and valid attribute
210 - * attribute configurations. It processes each prop and adds it to the
211 - * updatePayload.
212 - */
213 -function addNestedProperty(
214 - updatePayload: null | Object,
215 - nextProp: NestedNode,
216 - validAttributes: AttributeConfiguration,
217 -): $FlowFixMe {
218 - if (!nextProp) {
219 - return updatePayload;
220 - }
221 -
222 - if (enableFastAddPropertiesInDiffing) {
223 - return fastAddProperties(updatePayload, nextProp, validAttributes);
224 - }
225 -
226 - if (!isArray(nextProp)) {
227 - // Add each property of the leaf.
228 - return slowAddProperties(updatePayload, nextProp, validAttributes);
229 - }
230 -
231 - for (let i = 0; i < nextProp.length; i++) {
232 - // Add all the properties of the array.
233 - updatePayload = addNestedProperty(
234 - updatePayload,
235 - nextProp[i],
236 - validAttributes,
237 - );
238 - }
239 -
240 - return updatePayload;
241 -}
242 -
203 /**
204 * clearNestedProperty takes a single set of props and valid attributes. It
205 * adds a null sentinel to the updatePayload, for each prop key.
@@ -349,7 +309,7 @@ function diffProperties(
309 // Pattern match on: attributeConfig
310 if (typeof attributeConfig !== 'object') {
311 // case: !Object is the default case
352 - if (enableShallowPropDiffing || defaultDiffer(prevProp, nextProp)) {
312 + if (defaultDiffer(prevProp, nextProp)) {
313 // a normal leaf has changed
314 (updatePayload || (updatePayload = ({}: {[string]: $FlowFixMe})))[
315 propKey
@@ -361,7 +321,6 @@ function diffProperties(
321 ) {
322 // case: CustomAttributeConfiguration
323 const shouldUpdate =
364 - enableShallowPropDiffing ||
324 prevProp === undefined ||
325 (typeof attributeConfig.diff === 'function'
326 ? attributeConfig.diff(prevProp, nextProp)
@@ -452,7 +411,7 @@ function diffProperties(
411 return updatePayload;
412 }
413
455 -function fastAddProperties(
414 +function addNestedProperty(
415 payload: null | Object,
416 props: Object,
417 validAttributes: AttributeConfiguration,
@@ -460,7 +419,7 @@ function fastAddProperties(
419 // Flatten nested style props.
420 if (isArray(props)) {
421 for (let i = 0; i < props.length; i++) {
463 - payload = fastAddProperties(payload, props[i], validAttributes);
422 + payload = addNestedProperty(payload, props[i], validAttributes);
423 }
424 return payload;
425 }
@@ -507,23 +466,12 @@ function fastAddProperties(
466 continue;
467 }
468
510 - payload = fastAddProperties(payload, prop, attributeConfig);
469 + payload = addNestedProperty(payload, prop, attributeConfig);
470 }
471
472 return payload;
473 }
474
516 -/**
517 - * addProperties adds all the valid props to the payload after being processed.
518 - */
519 -function slowAddProperties(
520 - updatePayload: null | Object,
521 - props: Object,
522 - validAttributes: AttributeConfiguration,
523 -): null | Object {
524 - return diffProperties(updatePayload, emptyObject, props, validAttributes);
525 -}
526 -
475 /**
476 * clearProperties clears all the previous props by adding a null sentinel
477 * to the payload for each valid key.
@@ -533,7 +481,6 @@ function clearProperties(
481 prevProps: Object,
482 validAttributes: AttributeConfiguration,
483 ): null | Object {
536 - // TODO: Fast path
484 return diffProperties(updatePayload, prevProps, emptyObject, validAttributes);
485 }
486
@@ -541,7 +488,7 @@ export function create(
488 props: Object,
489 validAttributes: AttributeConfiguration,
490 ): null | Object {
544 - return fastAddProperties(null, props, validAttributes);
491 + return addNestedProperty(null, props, validAttributes);
492 }
493
494 export function diff(
packages/react-native-renderer/src/__tests__/ReactNativeAttributePayloadFabric-test.internal.js
-3
@@ -210,7 +210,6 @@ describe('ReactNativeAttributePayloadFabric.diff', () => {
210 expect(diff({a: 1}, {b: 2}, {})).toEqual(null);
211 });
212
213 - // @gate !enableShallowPropDiffing
213 it('should use the diff attribute', () => {
214 const diffA = jest.fn((a, b) => true);
215 const diffB = jest.fn((a, b) => false);
@@ -235,7 +234,6 @@ describe('ReactNativeAttributePayloadFabric.diff', () => {
234 expect(diffB).not.toBeCalled();
235 });
236
238 - // @gate !enableShallowPropDiffing
237 it('should do deep diffs of Objects by default', () => {
238 expect(
239 diff(
@@ -433,7 +431,6 @@ describe('ReactNativeAttributePayloadFabric.diff', () => {
431 ).toEqual(null);
432 });
433
436 - // @gate !enableShallowPropDiffing
434 it('should skip deeply-nested changed functions', () => {
435 expect(
436 diff(
packages/shared/ReactFeatureFlags.js
-3
@@ -141,8 +141,6 @@ export const passChildrenWhenCloningPersistedNodes = false;
141 */
142 export const enablePersistedModeClonedFlag = false;
143
144 -export const enableShallowPropDiffing = false;
145 -
144 export const enableEagerAlternateStateNodeCleanup = true;
145
146 /**
@@ -159,7 +157,6 @@ export const transitionLaneExpirationMs = 5000;
157 */
158 export const enableInfiniteRenderLoopDetection = false;
159
162 -export const enableFastAddPropertiesInDiffing = true;
160 export const enableLazyPublicInstanceInFabric = false;
161
162 export const enableFragmentRefs = __EXPERIMENTAL__;
packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js
-2
@@ -21,10 +21,8 @@ export const alwaysThrottleRetries = __VARIANT__;
21 export const enableObjectFiber = __VARIANT__;
22 export const enableHiddenSubtreeInsertionEffectCleanup = __VARIANT__;
23 export const enablePersistedModeClonedFlag = __VARIANT__;
24 -export const enableShallowPropDiffing = __VARIANT__;
24 export const enableEagerAlternateStateNodeCleanup = __VARIANT__;
25 export const passChildrenWhenCloningPersistedNodes = __VARIANT__;
27 -export const enableFastAddPropertiesInDiffing = __VARIANT__;
26 export const enableLazyPublicInstanceInFabric = __VARIANT__;
27 export const renameElementSymbol = __VARIANT__;
28 export const enableFragmentRefs = __VARIANT__;
packages/shared/forks/ReactFeatureFlags.native-fb.js
-2
@@ -23,10 +23,8 @@ export const {
23 enableHiddenSubtreeInsertionEffectCleanup,
24 enableObjectFiber,
25 enablePersistedModeClonedFlag,
26 - enableShallowPropDiffing,
26 enableEagerAlternateStateNodeCleanup,
27 passChildrenWhenCloningPersistedNodes,
29 - enableFastAddPropertiesInDiffing,
28 enableLazyPublicInstanceInFabric,
29 renameElementSymbol,
30 enableFragmentRefs,
packages/shared/forks/ReactFeatureFlags.native-oss.js
-2
@@ -48,7 +48,6 @@ export const enableRetryLaneExpiration = false;
48 export const enableSchedulingProfiler = __PROFILE__;
49 export const enableComponentPerformanceTrack = false;
50 export const enableScopeAPI = false;
51 -export const enableShallowPropDiffing = false;
51 export const enableEagerAlternateStateNodeCleanup = false;
52 export const enableSuspenseAvoidThisFallback = false;
53 export const enableSuspenseCallback = false;
@@ -69,7 +68,6 @@ export const enableYieldingBeforePassive = false;
68 export const enableThrottledScheduling = false;
69 export const enableViewTransition = false;
70 export const enableGestureTransition = false;
72 -export const enableFastAddPropertiesInDiffing = false;
71 export const enableLazyPublicInstanceInFabric = false;
72 export const enableScrollEndPolyfill = true;
73 export const enableSuspenseyImages = false;
packages/shared/forks/ReactFeatureFlags.test-renderer.js
-2
@@ -61,7 +61,6 @@ export const disableClientCache = true;
61 export const enableInfiniteRenderLoopDetection = false;
62
63 export const renameElementSymbol = true;
64 -export const enableShallowPropDiffing = false;
64 export const enableEagerAlternateStateNodeCleanup = false;
65
66 export const enableYieldingBeforePassive = true;
@@ -69,7 +68,6 @@ export const enableYieldingBeforePassive = true;
68 export const enableThrottledScheduling = false;
69 export const enableViewTransition = false;
70 export const enableGestureTransition = false;
72 -export const enableFastAddPropertiesInDiffing = true;
71 export const enableLazyPublicInstanceInFabric = false;
72 export const enableScrollEndPolyfill = true;
73 export const enableSuspenseyImages = false;
packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js
-2
@@ -46,7 +46,6 @@ export const enableRetryLaneExpiration = false;
46 export const enableSchedulingProfiler = __PROFILE__;
47 export const enableComponentPerformanceTrack = false;
48 export const enableScopeAPI = false;
49 -export const enableShallowPropDiffing = false;
49 export const enableEagerAlternateStateNodeCleanup = false;
50 export const enableSuspenseAvoidThisFallback = false;
51 export const enableSuspenseCallback = false;
@@ -66,7 +65,6 @@ export const enableYieldingBeforePassive = false;
65 export const enableThrottledScheduling = false;
66 export const enableViewTransition = false;
67 export const enableGestureTransition = false;
69 -export const enableFastAddPropertiesInDiffing = false;
68 export const enableLazyPublicInstanceInFabric = false;
69 export const enableScrollEndPolyfill = true;
70 export const enableSuspenseyImages = false;
packages/shared/forks/ReactFeatureFlags.test-renderer.www.js
-2
@@ -70,7 +70,6 @@ export const disableDefaultPropsExceptForClasses = true;
70 export const renameElementSymbol = false;
71
72 export const enableObjectFiber = false;
73 -export const enableShallowPropDiffing = false;
73 export const enableEagerAlternateStateNodeCleanup = false;
74
75 export const enableHydrationLaneScheduling = true;
@@ -80,7 +79,6 @@ export const enableYieldingBeforePassive = false;
79 export const enableThrottledScheduling = false;
80 export const enableViewTransition = false;
81 export const enableGestureTransition = false;
83 -export const enableFastAddPropertiesInDiffing = false;
82 export const enableLazyPublicInstanceInFabric = false;
83 export const enableScrollEndPolyfill = true;
84 export const enableSuspenseyImages = false;
packages/shared/forks/ReactFeatureFlags.www.js
-3
@@ -33,7 +33,6 @@ export const {
33 retryLaneExpirationMs,
34 syncLaneExpirationMs,
35 transitionLaneExpirationMs,
36 - enableFastAddPropertiesInDiffing,
36 enableViewTransition,
37 enableComponentPerformanceTrack,
38 enableScrollEndPolyfill,
@@ -105,8 +104,6 @@ export const enableReactTestRendererWarning = false;
104
105 export const disableLegacyMode = true;
106
108 -export const enableShallowPropDiffing = false;
109 -
107 export const enableEagerAlternateStateNodeCleanup = false;
108
109 export const enableLazyPublicInstanceInFabric = false;