@samitouri / QOS-React / commits / ef8894452b

Rollout enablePersistedModeClonedFlag (#34520)

## Summary Experimentation has completed for this at Meta and we've observed positive impact on key React Native surfaces. ## How did you test this change? yarn flow fabric

Pieter De Baets committed Sep 30, 2025 at 12:34 UTC ef8894452b826f905d69e61435c6f2c30731bfa6
11 files changed +18 -43
packages/react-native-renderer/src/__tests__/ReactFabric-test.internal.js
+12 -3
@@ -287,7 +287,6 @@ describe('ReactFabric', () => {
287 expect(nativeFabricUIManager.completeRoot).toBeCalled();
288 });
289
290 - // @gate enablePersistedModeClonedFlag
290 it('should not clone nodes when layout effects are used', async () => {
291 const View = createReactNativeComponentClass('RCTView', () => ({
292 validAttributes: {foo: true},
@@ -305,6 +304,8 @@ describe('ReactFabric', () => {
304 <ComponentWithEffect />
305 </View>,
306 11,
307 + null,
308 + true,
309 ),
310 );
311 expect(nativeFabricUIManager.completeRoot).toBeCalled();
@@ -316,6 +317,8 @@ describe('ReactFabric', () => {
317 <ComponentWithEffect />
318 </View>,
319 11,
320 + null,
321 + true,
322 ),
323 );
324 expect(nativeFabricUIManager.cloneNode).not.toBeCalled();
@@ -327,7 +330,6 @@ describe('ReactFabric', () => {
330 expect(nativeFabricUIManager.completeRoot).not.toBeCalled();
331 });
332
330 - // @gate enablePersistedModeClonedFlag
333 it('should not clone nodes when insertion effects are used', async () => {
334 const View = createReactNativeComponentClass('RCTView', () => ({
335 validAttributes: {foo: true},
@@ -345,6 +347,8 @@ describe('ReactFabric', () => {
347 <ComponentWithRef />
348 </View>,
349 11,
350 + null,
351 + true,
352 ),
353 );
354 expect(nativeFabricUIManager.completeRoot).toBeCalled();
@@ -356,6 +360,8 @@ describe('ReactFabric', () => {
360 <ComponentWithRef />
361 </View>,
362 11,
363 + null,
364 + true,
365 ),
366 );
367 expect(nativeFabricUIManager.cloneNode).not.toBeCalled();
@@ -367,7 +373,6 @@ describe('ReactFabric', () => {
373 expect(nativeFabricUIManager.completeRoot).not.toBeCalled();
374 });
375
370 - // @gate enablePersistedModeClonedFlag
376 it('should not clone nodes when useImperativeHandle is used', async () => {
377 const View = createReactNativeComponentClass('RCTView', () => ({
378 validAttributes: {foo: true},
@@ -387,6 +392,8 @@ describe('ReactFabric', () => {
392 <ComponentWithImperativeHandle ref={ref} />
393 </View>,
394 11,
395 + null,
396 + true,
397 ),
398 );
399 expect(nativeFabricUIManager.completeRoot).toBeCalled();
@@ -399,6 +406,8 @@ describe('ReactFabric', () => {
406 <ComponentWithImperativeHandle ref={ref} />
407 </View>,
408 11,
409 + null,
410 + true,
411 ),
412 );
413 expect(nativeFabricUIManager.cloneNode).not.toBeCalled();
packages/react-reconciler/src/ReactFiberCommitWork.js
+1 -5
@@ -48,7 +48,6 @@ import {
48 alwaysThrottleRetries,
49 enableCreateEventHandleAPI,
50 enableHiddenSubtreeInsertionEffectCleanup,
51 - enablePersistedModeClonedFlag,
51 enableProfilerTimer,
52 enableProfilerCommitHooks,
53 enableSuspenseCallback,
@@ -1969,10 +1968,7 @@ function recursivelyTraverseMutationEffects(
1968 }
1969 }
1970
1972 - if (
1973 - parentFiber.subtreeFlags &
1974 - (enablePersistedModeClonedFlag ? MutationMask | Cloned : MutationMask)
1975 - ) {
1971 + if (parentFiber.subtreeFlags & (MutationMask | Cloned)) {
1972 let child = parentFiber.child;
1973 while (child !== null) {
1974 commitMutationEffectsOnFiber(child, root, lanes);
packages/react-reconciler/src/ReactFiberCompleteWork.js
+5 -21
@@ -35,7 +35,6 @@ import {
35 enableLegacyHidden,
36 enableSuspenseCallback,
37 enableScopeAPI,
38 - enablePersistedModeClonedFlag,
38 enableProfilerTimer,
39 enableTransitionTracing,
40 passChildrenWhenCloningPersistedNodes,
@@ -92,7 +91,6 @@ import {
91 Snapshot,
92 ChildDeletion,
93 StaticMask,
95 - MutationMask,
94 Passive,
95 ForceClientRender,
96 MaySuspendCommit,
@@ -205,7 +203,7 @@ function markUpdate(workInProgress: Fiber) {
203 * it received an update that requires a clone of the tree above.
204 */
205 function markCloned(workInProgress: Fiber) {
208 - if (supportsPersistence && enablePersistedModeClonedFlag) {
206 + if (supportsPersistence) {
207 workInProgress.flags |= Cloned;
208 }
209 }
@@ -227,9 +225,7 @@ function doesRequireClone(current: null | Fiber, completedWork: Fiber) {
225 // then we only have to check the `completedWork.subtreeFlags`.
226 let child = completedWork.child;
227 while (child !== null) {
230 - const checkedFlags = enablePersistedModeClonedFlag
231 - ? Cloned | Visibility | Placement | ChildDeletion
232 - : MutationMask;
228 + const checkedFlags = Cloned | Visibility | Placement | ChildDeletion;
229 if (
230 (child.flags & checkedFlags) !== NoFlags ||
231 (child.subtreeFlags & checkedFlags) !== NoFlags
@@ -526,16 +522,9 @@ function updateHostComponent(
522 markUpdate(workInProgress);
523 }
524 workInProgress.stateNode = newInstance;
529 - if (!requiresClone) {
530 - if (!enablePersistedModeClonedFlag) {
531 - // If there are no other effects in this tree, we need to flag this node as having one.
532 - // Even though we're not going to use it for anything.
533 - // Otherwise parents won't know that there are new children to propagate upwards.
534 - markUpdate(workInProgress);
535 - }
536 - } else if (
537 - !passChildrenWhenCloningPersistedNodes ||
538 - hasOffscreenComponentChild
525 + if (
526 + requiresClone &&
527 + (!passChildrenWhenCloningPersistedNodes || hasOffscreenComponentChild)
528 ) {
529 // If children have changed, we have to add them all to the set.
530 appendAllChildren(
@@ -693,11 +682,6 @@ function updateHostText(
682 currentHostContext,
683 workInProgress,
684 );
696 - if (!enablePersistedModeClonedFlag) {
697 - // We'll have to mark it as having an effect, even though we won't use the effect for anything.
698 - // This lets the parents know that at least one of their children has changed.
699 - markUpdate(workInProgress);
700 - }
685 } else {
686 workInProgress.stateNode = current.stateNode;
687 }
packages/shared/ReactFeatureFlags.js
-6
@@ -129,12 +129,6 @@ export const alwaysThrottleRetries: boolean = true;
129
130 export const passChildrenWhenCloningPersistedNodes: boolean = false;
131
132 -/**
133 - * Enables a new Fiber flag used in persisted mode to reduce the number
134 - * of cloned host components.
135 - */
136 -export const enablePersistedModeClonedFlag: boolean = false;
137 -
132 export const enableEagerAlternateStateNodeCleanup: boolean = true;
133
134 /**
packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js
-1
@@ -20,7 +20,6 @@
20 export const alwaysThrottleRetries = __VARIANT__;
21 export const enableObjectFiber = __VARIANT__;
22 export const enableHiddenSubtreeInsertionEffectCleanup = __VARIANT__;
23 -export const enablePersistedModeClonedFlag = __VARIANT__;
23 export const enableEagerAlternateStateNodeCleanup = __VARIANT__;
24 export const passChildrenWhenCloningPersistedNodes = __VARIANT__;
25 export const renameElementSymbol = __VARIANT__;
packages/shared/forks/ReactFeatureFlags.native-fb.js
-1
@@ -22,7 +22,6 @@ export const {
22 alwaysThrottleRetries,
23 enableHiddenSubtreeInsertionEffectCleanup,
24 enableObjectFiber,
25 - enablePersistedModeClonedFlag,
25 enableEagerAlternateStateNodeCleanup,
26 passChildrenWhenCloningPersistedNodes,
27 renameElementSymbol,
packages/shared/forks/ReactFeatureFlags.native-oss.js
-1
@@ -38,7 +38,6 @@ export const enableLegacyFBSupport: boolean = false;
38 export const enableLegacyHidden: boolean = false;
39 export const enableNoCloningMemoCache: boolean = false;
40 export const enableObjectFiber: boolean = false;
41 -export const enablePersistedModeClonedFlag: boolean = false;
41 export const enablePostpone: boolean = false;
42 export const enableReactTestRendererWarning: boolean = false;
43 export const enableRetryLaneExpiration: boolean = false;
packages/shared/forks/ReactFeatureFlags.test-renderer.js
-1
@@ -53,7 +53,6 @@ export const enableFizzExternalRuntime: boolean = true;
53 export const alwaysThrottleRetries: boolean = true;
54
55 export const passChildrenWhenCloningPersistedNodes: boolean = false;
56 -export const enablePersistedModeClonedFlag: boolean = false;
56 export const disableClientCache: boolean = true;
57
58 export const enableInfiniteRenderLoopDetection: boolean = false;
packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js
-1
@@ -33,7 +33,6 @@ export const enableLegacyFBSupport = false;
33 export const enableLegacyHidden = false;
34 export const enableNoCloningMemoCache = false;
35 export const enableObjectFiber = false;
36 -export const enablePersistedModeClonedFlag = false;
36 export const enablePostpone = false;
37 export const enableProfilerCommitHooks = __PROFILE__;
38 export const enableProfilerNestedUpdatePhase = __PROFILE__;
packages/shared/forks/ReactFeatureFlags.test-renderer.www.js
-1
@@ -54,7 +54,6 @@ export const enableFizzExternalRuntime: boolean = false;
54 export const alwaysThrottleRetries: boolean = true;
55
56 export const passChildrenWhenCloningPersistedNodes: boolean = false;
57 -export const enablePersistedModeClonedFlag: boolean = false;
57 export const disableClientCache: boolean = true;
58
59 export const enableInfiniteRenderLoopDetection: boolean = false;
packages/shared/forks/ReactFeatureFlags.www.js
-2
@@ -93,8 +93,6 @@ export const enableFizzExternalRuntime: boolean = true;
93
94 export const passChildrenWhenCloningPersistedNodes: boolean = false;
95
96 -export const enablePersistedModeClonedFlag: boolean = false;
97 -
96 export const disableClientCache: boolean = true;
97
98 export const enableReactTestRendererWarning: boolean = false;