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;