Call cleanup of insertion effects when hidden (#30954)
Insertion effects do not unmount when a subtree is removed while offscreen. Current behavior for an insertion effect is if the component goes - *visible -> removed:* calls insertion effect cleanup - *visible -> offscreen -> removed:* insertion effect cleanup is never called This makes it so we always call insertion effect cleanup when removing the component. Likely also fixes https://github.com/facebook/react/issues/26670 --------- Co-authored-by: Rick Hanlon <rickhanlonii@fb.com>
Jan Kassens committed
Sep 13, 2024 at 13:18 UTC
d3d4d3a46b014ab0f6edc443c19fcdba09105f20
13 files changed
+366
-5
packages/react-reconciler/src/ReactFiberCommitWork.js
+74
-1
@@ -40,6 +40,7 @@ import type {
40
import {
41
alwaysThrottleRetries,
42
enableCreateEventHandleAPI,
43
+ enableHiddenSubtreeInsertionEffectCleanup,
44
enablePersistedModeClonedFlag,
45
enableProfilerTimer,
46
enableProfilerCommitHooks,
@@ -147,6 +148,7 @@ import {
148
getExecutionContext,
149
CommitContext,
150
NoContext,
151
+ setIsRunningInsertionEffect,
152
} from './ReactFiberWorkLoop';
153
import {
154
NoFlags as NoHookEffect,
@@ -1324,7 +1326,78 @@ function commitDeletionEffectsOnFiber(
1326
case ForwardRef:
1327
case MemoComponent:
1328
case SimpleMemoComponent: {
1327
- if (!offscreenSubtreeWasHidden) {
1329
+ if (enableHiddenSubtreeInsertionEffectCleanup) {
1330
+ // When deleting a fiber, we may need to destroy insertion or layout effects.
1331
+ // Insertion effects are not destroyed on hidden, only when destroyed, so now
1332
+ // we need to destroy them. Layout effects are destroyed when hidden, so
1333
+ // we only need to destroy them if the tree is visible.
1334
+ const updateQueue: FunctionComponentUpdateQueue | null =
1335
+ (deletedFiber.updateQueue: any);
1336
+ if (updateQueue !== null) {
1337
+ const lastEffect = updateQueue.lastEffect;
1338
+ if (lastEffect !== null) {
1339
+ const firstEffect = lastEffect.next;
1340
+
1341
+ let effect = firstEffect;
1342
+ do {
1343
+ const tag = effect.tag;
1344
+ const inst = effect.inst;
1345
+ const destroy = inst.destroy;
1346
+ if (destroy !== undefined) {
1347
+ if ((tag & HookInsertion) !== NoHookEffect) {
1348
+ // TODO: add insertion effect marks and profiling.
1349
+ if (__DEV__) {
1350
+ setIsRunningInsertionEffect(true);
1351
+ }
1352
+
1353
+ inst.destroy = undefined;
1354
+ safelyCallDestroy(
1355
+ deletedFiber,
1356
+ nearestMountedAncestor,
1357
+ destroy,
1358
+ );
1359
+
1360
+ if (__DEV__) {
1361
+ setIsRunningInsertionEffect(false);
1362
+ }
1363
+ } else if (
1364
+ !offscreenSubtreeWasHidden &&
1365
+ (tag & HookLayout) !== NoHookEffect
1366
+ ) {
1367
+ // Offscreen fibers already unmounted their layout effects.
1368
+ // We only need to destroy layout effects for visible trees.
1369
+ if (enableSchedulingProfiler) {
1370
+ markComponentLayoutEffectUnmountStarted(deletedFiber);
1371
+ }
1372
+
1373
+ if (shouldProfile(deletedFiber)) {
1374
+ startLayoutEffectTimer();
1375
+ inst.destroy = undefined;
1376
+ safelyCallDestroy(
1377
+ deletedFiber,
1378
+ nearestMountedAncestor,
1379
+ destroy,
1380
+ );
1381
+ recordLayoutEffectDuration(deletedFiber);
1382
+ } else {
1383
+ inst.destroy = undefined;
1384
+ safelyCallDestroy(
1385
+ deletedFiber,
1386
+ nearestMountedAncestor,
1387
+ destroy,
1388
+ );
1389
+ }
1390
+
1391
+ if (enableSchedulingProfiler) {
1392
+ markComponentLayoutEffectUnmountStopped();
1393
+ }
1394
+ }
1395
+ }
1396
+ effect = effect.next;
1397
+ } while (effect !== firstEffect);
1398
+ }
1399
+ }
1400
+ } else if (!offscreenSubtreeWasHidden) {
1401
const updateQueue: FunctionComponentUpdateQueue | null =
1402
(deletedFiber.updateQueue: any);
1403
if (updateQueue !== null) {
packages/react-reconciler/src/__tests__/Activity-test.js
+85
@@ -7,6 +7,7 @@ let Activity;
7
let useState;
8
let useLayoutEffect;
9
let useEffect;
10
+let useInsertionEffect;
11
let useMemo;
12
let useRef;
13
let startTransition;
@@ -25,6 +26,7 @@ describe('Activity', () => {
26
LegacyHidden = React.unstable_LegacyHidden;
27
Activity = React.unstable_Activity;
28
useState = React.useState;
29
+ useInsertionEffect = React.useInsertionEffect;
30
useLayoutEffect = React.useLayoutEffect;
31
useEffect = React.useEffect;
32
useMemo = React.useMemo;
@@ -43,6 +45,13 @@ describe('Activity', () => {
45
}
46
47
function LoggedText({text, children}) {
48
+ useInsertionEffect(() => {
49
+ Scheduler.log(`mount insertion ${text}`);
50
+ return () => {
51
+ Scheduler.log(`unmount insertion ${text}`);
52
+ };
53
+ });
54
+
55
useEffect(() => {
56
Scheduler.log(`mount ${text}`);
57
return () => {
@@ -1436,6 +1445,63 @@ describe('Activity', () => {
1445
);
1446
});
1447
1448
+ // @gate enableActivity
1449
+ it('insertion effects are not disconnected when the visibility changes', async () => {
1450
+ function Child({step}) {
1451
+ useInsertionEffect(() => {
1452
+ Scheduler.log(`Commit mount [${step}]`);
1453
+ return () => {
1454
+ Scheduler.log(`Commit unmount [${step}]`);
1455
+ };
1456
+ }, [step]);
1457
+ return <Text text={step} />;
1458
+ }
1459
+
1460
+ function App({show, step}) {
1461
+ return (
1462
+ <Activity mode={show ? 'visible' : 'hidden'}>
1463
+ {useMemo(
1464
+ () => (
1465
+ <Child step={step} />
1466
+ ),
1467
+ [step],
1468
+ )}
1469
+ </Activity>
1470
+ );
1471
+ }
1472
+
1473
+ const root = ReactNoop.createRoot();
1474
+ await act(() => {
1475
+ root.render(<App show={true} step={1} />);
1476
+ });
1477
+ assertLog([1, 'Commit mount [1]']);
1478
+ expect(root).toMatchRenderedOutput(<span prop={1} />);
1479
+
1480
+ // Hide the tree. This will not unmount insertion effects.
1481
+ await act(() => {
1482
+ root.render(<App show={false} step={1} />);
1483
+ });
1484
+ assertLog([]);
1485
+ expect(root).toMatchRenderedOutput(<span hidden={true} prop={1} />);
1486
+
1487
+ // Update.
1488
+ await act(() => {
1489
+ root.render(<App show={false} step={2} />);
1490
+ });
1491
+ // The update is pre-rendered so insertion effects are fired
1492
+ assertLog([2, 'Commit unmount [1]', 'Commit mount [2]']);
1493
+ expect(root).toMatchRenderedOutput(<span hidden={true} prop={2} />);
1494
+
1495
+ // Reveal the tree.
1496
+ await act(() => {
1497
+ root.render(<App show={true} step={2} />);
1498
+ });
1499
+ // The update doesn't render because it was already pre-rendered, and the
1500
+ // insertion effect already fired.
1501
+ assertLog([]);
1502
+ expect(root).toMatchRenderedOutput(<span prop={2} />);
1503
+ });
1504
+
1505
describe('manual interactivity', () => {
1506
// @gate enableActivity
1507
it('should attach ref only for mode null', async () => {
@@ -1904,6 +1970,9 @@ describe('Activity', () => {
1970
'outer',
1971
'middle',
1972
'inner',
1973
+ 'mount insertion inner',
1974
+ 'mount insertion middle',
1975
+ 'mount insertion outer',
1976
'mount layout inner',
1977
'mount layout middle',
1978
'mount layout outer',
@@ -1964,6 +2033,22 @@ describe('Activity', () => {
2033
});
2034
2035
assertLog(['unmount layout inner', 'unmount inner']);
2036
+
2037
+ await act(() => {
2038
+ root.render(null);
2039
+ });
2040
+
2041
+ assertLog([
2042
+ 'unmount insertion outer',
2043
+ 'unmount layout outer',
2044
+ 'unmount insertion middle',
2045
+ 'unmount layout middle',
2046
+ ...(gate('enableHiddenSubtreeInsertionEffectCleanup')
2047
+ ? ['unmount insertion inner']
2048
+ : []),
2049
+ 'unmount outer',
2050
+ 'unmount middle',
2051
+ ]);
2052
});
2053
2054
// @gate enableActivity
packages/react-reconciler/src/__tests__/ReactHooksWithNoopRenderer-test.js
+53
@@ -19,6 +19,7 @@ let resolveText;
19
let ReactNoop;
20
let Scheduler;
21
let Suspense;
22
+let Activity;
23
let useState;
24
let useReducer;
25
let useEffect;
@@ -64,6 +65,7 @@ describe('ReactHooksWithNoopRenderer', () => {
65
useTransition = React.useTransition;
66
useDeferredValue = React.useDeferredValue;
67
Suspense = React.Suspense;
68
+ Activity = React.unstable_Activity;
69
ContinuousEventPriority =
70
require('react-reconciler/constants').ContinuousEventPriority;
71
if (gate(flags => flags.enableSuspenseList)) {
@@ -2997,6 +2999,57 @@ describe('ReactHooksWithNoopRenderer', () => {
2999
root.render(<NotInsertion />);
3000
});
3001
});
3002
+
3003
+ // @gate enableActivity
3004
+ it('warns when setState is called from offscreen deleted insertion effect cleanup', async () => {
3005
+ function App(props) {
3006
+ const [, setX] = useState(0);
3007
+ useInsertionEffect(() => {
3008
+ if (props.throw) {
3009
+ throw Error('No');
3010
+ }
3011
+ return () => {
3012
+ setX(1);
3013
+ };
3014
+ }, [props.throw, props.foo]);
3015
+ return null;
3016
+ }
3017
+
3018
+ const root = ReactNoop.createRoot();
3019
+ await act(() => {
3020
+ root.render(
3021
+ <Activity mode="hidden">
3022
+ <App foo="hello" />
3023
+ </Activity>,
3024
+ );
3025
+ });
3026
+
3027
+ if (gate(flags => flags.enableHiddenSubtreeInsertionEffectCleanup)) {
3028
+ await expect(async () => {
3029
+ await act(() => {
3030
+ root.render(<Activity mode="hidden" />);
3031
+ });
3032
+ }).toErrorDev(['useInsertionEffect must not schedule updates.']);
3033
+ } else {
3034
+ await expect(async () => {
3035
+ await act(() => {
3036
+ root.render(<Activity mode="hidden" />);
3037
+ });
3038
+ }).toErrorDev([]);
3039
+ }
3040
+
3041
+ // Should not warn for regular effects after throw.
3042
+ function NotInsertion() {
3043
+ const [, setX] = useState(0);
3044
+ useEffect(() => {
3045
+ setX(1);
3046
+ }, []);
3047
+ return null;
3048
+ }
3049
+ await act(() => {
3050
+ root.render(<NotInsertion />);
3051
+ });
3052
+ });
3053
});
3054
3055
describe('useLayoutEffect', () => {
packages/react-reconciler/src/__tests__/ReactSuspenseEffectsSemantics-test.js
+141
-4
@@ -148,6 +148,13 @@ describe('ReactSuspenseEffectsSemantics', () => {
148
149
function Text({children = null, text}) {
150
Scheduler.log(`Text:${text} render`);
151
+ React.useInsertionEffect(() => {
152
+ Scheduler.log(`Text:${text} create insertion`);
153
+ return () => {
154
+ Scheduler.log(`Text:${text} destroy insertion`);
155
+ };
156
+ }, []);
157
+
158
React.useLayoutEffect(() => {
159
Scheduler.log(`Text:${text} create layout`);
160
return () => {
@@ -268,6 +275,8 @@ describe('ReactSuspenseEffectsSemantics', () => {
275
'Suspend:Async',
276
'Text:Fallback render',
277
'Text:Outside render',
278
+ 'Text:Fallback create insertion',
279
+ 'Text:Outside create insertion',
280
'Text:Fallback create layout',
281
'Text:Outside create layout',
282
'App create layout',
@@ -298,7 +307,9 @@ describe('ReactSuspenseEffectsSemantics', () => {
307
'Text:Inside:Before render',
308
'AsyncText:Async render',
309
'ClassText:Inside:After render',
310
+ 'Text:Fallback destroy insertion',
311
'Text:Fallback destroy layout',
312
+ 'Text:Inside:Before create insertion',
313
'Text:Inside:Before create layout',
314
'AsyncText:Async create layout',
315
'ClassText:Inside:After componentDidMount',
@@ -320,9 +331,11 @@ describe('ReactSuspenseEffectsSemantics', () => {
331
});
332
assertLog([
333
'App destroy layout',
334
+ 'Text:Inside:Before destroy insertion',
335
'Text:Inside:Before destroy layout',
336
'AsyncText:Async destroy layout',
337
'ClassText:Inside:After componentWillUnmount',
338
+ 'Text:Outside destroy insertion',
339
'Text:Outside destroy layout',
340
'App destroy passive',
341
'Text:Inside:Before destroy passive',
@@ -395,6 +408,9 @@ describe('ReactSuspenseEffectsSemantics', () => {
408
'ClassText:Inside:After render',
409
'Text:Fallback render',
410
'Text:Outside render',
411
+ 'Text:Inside:Before create insertion',
412
+ 'Text:Fallback create insertion',
413
+ 'Text:Outside create insertion',
414
'Text:Inside:Before create layout',
415
'ClassText:Inside:After componentDidMount',
416
'Text:Fallback create layout',
@@ -420,6 +436,7 @@ describe('ReactSuspenseEffectsSemantics', () => {
436
});
437
assertLog([
438
'AsyncText:Async render',
439
+ 'Text:Fallback destroy insertion',
440
'Text:Fallback destroy layout',
441
'AsyncText:Async create layout',
442
'Text:Fallback destroy passive',
@@ -439,9 +456,11 @@ describe('ReactSuspenseEffectsSemantics', () => {
456
});
457
assertLog([
458
'App destroy layout',
459
+ 'Text:Inside:Before destroy insertion',
460
'Text:Inside:Before destroy layout',
461
'AsyncText:Async destroy layout',
462
'ClassText:Inside:After componentWillUnmount',
463
+ 'Text:Outside destroy insertion',
464
'Text:Outside destroy layout',
465
'App destroy passive',
466
'Text:Inside:Before destroy passive',
@@ -452,7 +471,7 @@ describe('ReactSuspenseEffectsSemantics', () => {
471
});
472
});
473
455
- describe('layout effects within a tree that re-suspends in an update', () => {
474
+ describe('effects within a tree that re-suspends in an update', () => {
475
// @gate enableLegacyCache && !disableLegacyMode
476
it('should not be destroyed or recreated in legacy roots', async () => {
477
function App({children = null}) {
@@ -490,6 +509,9 @@ describe('ReactSuspenseEffectsSemantics', () => {
509
'Text:Inside:Before render',
510
'Text:Inside:After render',
511
'Text:Outside render',
512
+ 'Text:Inside:Before create insertion',
513
+ 'Text:Inside:After create insertion',
514
+ 'Text:Outside create insertion',
515
'Text:Inside:Before create layout',
516
'Text:Inside:After create layout',
517
'Text:Outside create layout',
@@ -522,6 +544,7 @@ describe('ReactSuspenseEffectsSemantics', () => {
544
'Text:Inside:After render',
545
'Text:Fallback render',
546
'Text:Outside render',
547
+ 'Text:Fallback create insertion',
548
'Text:Fallback create layout',
549
'Text:Fallback create passive',
550
]);
@@ -553,6 +576,7 @@ describe('ReactSuspenseEffectsSemantics', () => {
576
});
577
assertLog([
578
'AsyncText:Async render',
579
+ 'Text:Fallback destroy insertion',
580
'Text:Fallback destroy layout',
581
'AsyncText:Async create layout',
582
'Text:Fallback destroy passive',
@@ -572,9 +596,12 @@ describe('ReactSuspenseEffectsSemantics', () => {
596
});
597
assertLog([
598
'App destroy layout',
599
+ 'Text:Inside:Before destroy insertion',
600
'Text:Inside:Before destroy layout',
601
'AsyncText:Async destroy layout',
602
+ 'Text:Inside:After destroy insertion',
603
'Text:Inside:After destroy layout',
604
+ 'Text:Outside destroy insertion',
605
'Text:Outside destroy layout',
606
'App destroy passive',
607
'Text:Inside:Before destroy passive',
@@ -620,6 +647,9 @@ describe('ReactSuspenseEffectsSemantics', () => {
647
'Text:Inside:Before render',
648
'Text:Inside:After render',
649
'Text:Outside render',
650
+ 'Text:Inside:Before create insertion',
651
+ 'Text:Inside:After create insertion',
652
+ 'Text:Outside create insertion',
653
'Text:Inside:Before create layout',
654
'Text:Inside:After create layout',
655
'Text:Outside create layout',
@@ -652,6 +682,7 @@ describe('ReactSuspenseEffectsSemantics', () => {
682
'Text:Outside render',
683
'Text:Inside:Before destroy layout',
684
'Text:Inside:After destroy layout',
685
+ 'Text:Fallback create insertion',
686
'Text:Fallback create layout',
687
]);
688
await waitForAll([
@@ -683,6 +714,7 @@ describe('ReactSuspenseEffectsSemantics', () => {
714
'Text:Inside:Before render',
715
'AsyncText:Async render',
716
'Text:Inside:After render',
717
+ 'Text:Fallback destroy insertion',
718
'Text:Fallback destroy layout',
719
'Text:Inside:Before create layout',
720
'AsyncText:Async create layout',
@@ -704,9 +736,12 @@ describe('ReactSuspenseEffectsSemantics', () => {
736
});
737
assertLog([
738
'App destroy layout',
739
+ 'Text:Inside:Before destroy insertion',
740
'Text:Inside:Before destroy layout',
741
'AsyncText:Async destroy layout',
742
+ 'Text:Inside:After destroy insertion',
743
'Text:Inside:After destroy layout',
744
+ 'Text:Outside destroy insertion',
745
'Text:Outside destroy layout',
746
'App destroy passive',
747
'Text:Inside:Before destroy passive',
@@ -893,6 +928,8 @@ describe('ReactSuspenseEffectsSemantics', () => {
928
'App render',
929
'Text:Outer render',
930
'Text:Inner render',
931
+ 'Text:Inner create insertion',
932
+ 'Text:Outer create insertion',
933
'Text:Inner create layout',
934
'Text:Outer create layout',
935
'App create layout',
@@ -919,6 +956,7 @@ describe('ReactSuspenseEffectsSemantics', () => {
956
'Text:Fallback render',
957
'Text:Outer destroy layout',
958
'Text:Inner destroy layout',
959
+ 'Text:Fallback create insertion',
960
'Text:Fallback create layout',
961
]);
962
await waitForAll([
@@ -946,6 +984,7 @@ describe('ReactSuspenseEffectsSemantics', () => {
984
'AsyncText:Async render',
985
'Text:Outer render',
986
'Text:Inner render',
987
+ 'Text:Fallback destroy insertion',
988
'Text:Fallback destroy layout',
989
'AsyncText:Async create layout',
990
'Text:Inner create layout',
@@ -968,7 +1007,9 @@ describe('ReactSuspenseEffectsSemantics', () => {
1007
assertLog([
1008
'App destroy layout',
1009
'AsyncText:Async destroy layout',
1010
+ 'Text:Outer destroy insertion',
1011
'Text:Outer destroy layout',
1012
+ 'Text:Inner destroy insertion',
1013
'Text:Inner destroy layout',
1014
'App destroy passive',
1015
'AsyncText:Async destroy passive',
@@ -1013,6 +1054,8 @@ describe('ReactSuspenseEffectsSemantics', () => {
1054
'App render',
1055
'Text:Outer render',
1056
'Text:MemoizedInner render',
1057
+ 'Text:MemoizedInner create insertion',
1058
+ 'Text:Outer create insertion',
1059
'Text:MemoizedInner create layout',
1060
'Text:Outer create layout',
1061
'App create layout',
@@ -1040,6 +1083,7 @@ describe('ReactSuspenseEffectsSemantics', () => {
1083
'Text:Fallback render',
1084
'Text:Outer destroy layout',
1085
'Text:MemoizedInner destroy layout',
1086
+ 'Text:Fallback create insertion',
1087
'Text:Fallback create layout',
1088
]);
1089
await waitForAll([
@@ -1066,6 +1110,7 @@ describe('ReactSuspenseEffectsSemantics', () => {
1110
assertLog([
1111
'AsyncText:Async render',
1112
'Text:Outer render',
1113
+ 'Text:Fallback destroy insertion',
1114
'Text:Fallback destroy layout',
1115
'AsyncText:Async create layout',
1116
'Text:MemoizedInner create layout',
@@ -1088,7 +1133,9 @@ describe('ReactSuspenseEffectsSemantics', () => {
1133
assertLog([
1134
'App destroy layout',
1135
'AsyncText:Async destroy layout',
1136
+ 'Text:Outer destroy insertion',
1137
'Text:Outer destroy layout',
1138
+ 'Text:MemoizedInner destroy insertion',
1139
'Text:MemoizedInner destroy layout',
1140
'App destroy passive',
1141
'AsyncText:Async destroy passive',
@@ -1119,6 +1166,8 @@ describe('ReactSuspenseEffectsSemantics', () => {
1166
assertLog([
1167
'Text:Outer render',
1168
'Text:Inner render',
1169
+ 'Text:Outer create insertion',
1170
+ 'Text:Inner create insertion',
1171
'Text:Outer create layout',
1172
'Text:Inner create layout',
1173
'Text:Outer create passive',
@@ -1143,6 +1192,7 @@ describe('ReactSuspenseEffectsSemantics', () => {
1192
'Suspend:InnerAsync_1',
1193
'Text:InnerFallback render',
1194
'Text:Inner destroy layout',
1195
+ 'Text:InnerFallback create insertion',
1196
'Text:InnerFallback create layout',
1197
'Text:InnerFallback create passive',
1198
@@ -1175,6 +1225,7 @@ describe('ReactSuspenseEffectsSemantics', () => {
1225
'Text:OuterFallback render',
1226
'Text:Outer destroy layout',
1227
'Text:InnerFallback destroy layout',
1228
+ 'Text:OuterFallback create insertion',
1229
'Text:OuterFallback create layout',
1230
'Text:OuterFallback create passive',
1231
@@ -1267,7 +1318,7 @@ describe('ReactSuspenseEffectsSemantics', () => {
1318
'Text:Inner render',
1319
'Suspend:InnerAsync_2',
1320
'Text:InnerFallback render',
1270
-
1321
+ 'Text:OuterFallback destroy insertion',
1322
'Text:OuterFallback destroy layout',
1323
'Text:Outer create layout',
1324
'AsyncText:OuterAsync_1 create layout',
@@ -1295,6 +1346,7 @@ describe('ReactSuspenseEffectsSemantics', () => {
1346
assertLog([
1347
'Text:Inner render',
1348
'AsyncText:InnerAsync_2 render',
1349
+ 'Text:InnerFallback destroy insertion',
1350
'Text:InnerFallback destroy layout',
1351
'Text:Inner create layout',
1352
'AsyncText:InnerAsync_2 create layout',
@@ -1327,6 +1379,7 @@ describe('ReactSuspenseEffectsSemantics', () => {
1379
'AsyncText:OuterAsync_1 destroy layout',
1380
'Text:Inner destroy layout',
1381
'AsyncText:InnerAsync_2 destroy layout',
1382
+ 'Text:OuterFallback create insertion',
1383
'Text:OuterFallback create layout',
1384
'Text:OuterFallback create passive',
1385
@@ -1358,6 +1411,7 @@ describe('ReactSuspenseEffectsSemantics', () => {
1411
'AsyncText:OuterAsync_2 render',
1412
'Text:Inner render',
1413
'AsyncText:InnerAsync_2 render',
1414
+ 'Text:OuterFallback destroy insertion',
1415
'Text:OuterFallback destroy layout',
1416
'Text:Outer create layout',
1417
'AsyncText:OuterAsync_2 create layout',
@@ -1397,6 +1451,8 @@ describe('ReactSuspenseEffectsSemantics', () => {
1451
assertLog([
1452
'Text:Outer render',
1453
'Text:Inner render',
1454
+ 'Text:Outer create insertion',
1455
+ 'Text:Inner create insertion',
1456
'Text:Outer create layout',
1457
'Text:Inner create layout',
1458
'Text:Outer create passive',
@@ -1421,6 +1477,7 @@ describe('ReactSuspenseEffectsSemantics', () => {
1477
'Suspend:InnerAsync_1',
1478
'Text:InnerFallback render',
1479
'Text:Inner destroy layout',
1480
+ 'Text:InnerFallback create insertion',
1481
'Text:InnerFallback create layout',
1482
'Text:InnerFallback create passive',
1483
@@ -1452,6 +1509,7 @@ describe('ReactSuspenseEffectsSemantics', () => {
1509
'Text:OuterFallback render',
1510
'Text:Outer destroy layout',
1511
'Text:InnerFallback destroy layout',
1512
+ 'Text:OuterFallback create insertion',
1513
'Text:OuterFallback create layout',
1514
'Text:OuterFallback create passive',
1515
@@ -1484,7 +1542,11 @@ describe('ReactSuspenseEffectsSemantics', () => {
1542
'AsyncText:OuterAsync_1 render',
1543
'Text:Inner render',
1544
'AsyncText:InnerAsync_1 render',
1545
+ 'Text:OuterFallback destroy insertion',
1546
'Text:OuterFallback destroy layout',
1547
+ ...(gate(flags => flags.enableHiddenSubtreeInsertionEffectCleanup)
1548
+ ? ['Text:InnerFallback destroy insertion']
1549
+ : []),
1550
'Text:Outer create layout',
1551
'AsyncText:OuterAsync_1 create layout',
1552
'Text:Inner create layout',
@@ -1534,6 +1596,8 @@ describe('ReactSuspenseEffectsSemantics', () => {
1596
assertLog([
1597
'Text:Inside render',
1598
'Text:Outside render',
1599
+ 'Text:Inside create insertion',
1600
+ 'Text:Outside create insertion',
1601
'Text:Inside create layout',
1602
'Text:Outside create layout',
1603
'Text:Inside create passive',
@@ -1558,6 +1622,8 @@ describe('ReactSuspenseEffectsSemantics', () => {
1622
'Text:Fallback:Outside render',
1623
'Text:Outside render',
1624
'Text:Inside destroy layout',
1625
+ 'Text:Fallback:Inside create insertion',
1626
+ 'Text:Fallback:Outside create insertion',
1627
'Text:Fallback:Inside create layout',
1628
'Text:Fallback:Outside create layout',
1629
]);
@@ -1596,6 +1662,7 @@ describe('ReactSuspenseEffectsSemantics', () => {
1662
'Text:Fallback:Outside render',
1663
'Text:Outside render',
1664
'Text:Fallback:Inside destroy layout',
1665
+ 'Text:Fallback:Fallback create insertion',
1666
'Text:Fallback:Fallback create layout',
1667
]);
1668
await waitForAll([
@@ -1629,7 +1696,12 @@ describe('ReactSuspenseEffectsSemantics', () => {
1696
assertLog([
1697
'Text:Inside render',
1698
'AsyncText:OutsideAsync render',
1699
+ ...(gate(flags => flags.enableHiddenSubtreeInsertionEffectCleanup)
1700
+ ? ['Text:Fallback:Inside destroy insertion']
1701
+ : []),
1702
+ 'Text:Fallback:Fallback destroy insertion',
1703
'Text:Fallback:Fallback destroy layout',
1704
+ 'Text:Fallback:Outside destroy insertion',
1705
'Text:Fallback:Outside destroy layout',
1706
'Text:Inside create layout',
1707
'AsyncText:OutsideAsync create layout',
@@ -1677,6 +1749,8 @@ describe('ReactSuspenseEffectsSemantics', () => {
1749
assertLog([
1750
'Text:Inside render',
1751
'Text:Outside render',
1752
+ 'Text:Inside create insertion',
1753
+ 'Text:Outside create insertion',
1754
'Text:Inside create layout',
1755
'Text:Outside create layout',
1756
'Text:Inside create passive',
@@ -1707,6 +1781,8 @@ describe('ReactSuspenseEffectsSemantics', () => {
1781
'Text:Fallback:Outside render',
1782
'Text:Outside render',
1783
'Text:Inside destroy layout',
1784
+ 'Text:Fallback:Fallback create insertion',
1785
+ 'Text:Fallback:Outside create insertion',
1786
'Text:Fallback:Fallback create layout',
1787
'Text:Fallback:Outside create layout',
1788
'Text:Fallback:Fallback create passive',
@@ -1737,7 +1813,9 @@ describe('ReactSuspenseEffectsSemantics', () => {
1813
assertLog([
1814
'Text:Fallback:Inside render',
1815
'AsyncText:FallbackAsync render',
1816
+ 'Text:Fallback:Fallback destroy insertion',
1817
'Text:Fallback:Fallback destroy layout',
1818
+ 'Text:Fallback:Inside create insertion',
1819
'Text:Fallback:Inside create layout',
1820
'AsyncText:FallbackAsync create layout',
1821
'Text:Fallback:Fallback destroy passive',
@@ -1761,8 +1839,10 @@ describe('ReactSuspenseEffectsSemantics', () => {
1839
assertLog([
1840
'Text:Inside render',
1841
'AsyncText:OutsideAsync render',
1842
+ 'Text:Fallback:Inside destroy insertion',
1843
'Text:Fallback:Inside destroy layout',
1844
'AsyncText:FallbackAsync destroy layout',
1845
+ 'Text:Fallback:Outside destroy insertion',
1846
'Text:Fallback:Outside destroy layout',
1847
'Text:Inside create layout',
1848
'AsyncText:OutsideAsync create layout',
@@ -1807,6 +1887,8 @@ describe('ReactSuspenseEffectsSemantics', () => {
1887
assertLog([
1888
'Text:Inside render',
1889
'Text:Outside render',
1890
+ 'Text:Inside create insertion',
1891
+ 'Text:Outside create insertion',
1892
'Text:Inside create layout',
1893
'Text:Outside create layout',
1894
'Text:Inside create passive',
@@ -1828,6 +1910,7 @@ describe('ReactSuspenseEffectsSemantics', () => {
1910
'Text:Fallback render',
1911
'Text:Outside render',
1912
'Text:Inside destroy layout',
1913
+ 'Text:Fallback create insertion',
1914
'Text:Fallback create layout',
1915
]);
1916
await waitForAll([
@@ -1850,6 +1933,7 @@ describe('ReactSuspenseEffectsSemantics', () => {
1933
});
1934
assertLog([
1935
'Text:Inside render',
1936
+ 'Text:Fallback destroy insertion',
1937
'Text:Fallback destroy layout',
1938
'Text:Inside create layout',
1939
'Text:Fallback destroy passive',
@@ -1916,6 +2000,8 @@ describe('ReactSuspenseEffectsSemantics', () => {
2000
'ThrowsInDidMount render',
2001
'Text:Inside render',
2002
'Text:Outside render',
2003
+ 'Text:Inside create insertion',
2004
+ 'Text:Outside create insertion',
2005
'ThrowsInDidMount componentDidMount',
2006
'Text:Inside create layout',
2007
'Text:Outside create layout',
@@ -1949,6 +2035,7 @@ describe('ReactSuspenseEffectsSemantics', () => {
2035
'Text:Outside render',
2036
'ThrowsInDidMount componentWillUnmount',
2037
'Text:Inside destroy layout',
2038
+ 'Text:Fallback create insertion',
2039
'Text:Fallback create layout',
2040
'Text:Fallback create passive',
2041
@@ -1974,6 +2061,7 @@ describe('ReactSuspenseEffectsSemantics', () => {
2061
'AsyncText:Async render',
2062
'ThrowsInDidMount render',
2063
'Text:Inside render',
2064
+ 'Text:Fallback destroy insertion',
2065
'Text:Fallback destroy layout',
2066
'AsyncText:Async create layout',
2067
@@ -1986,11 +2074,13 @@ describe('ReactSuspenseEffectsSemantics', () => {
2074
'Text:Fallback destroy passive',
2075
'AsyncText:Async create passive',
2076
1989
- // Destroy layout and passive effects in the errored tree.
2077
+ // Destroy insertion, layout, and passive effects in the errored tree.
2078
'App destroy layout',
2079
'AsyncText:Async destroy layout',
2080
'ThrowsInDidMount componentWillUnmount',
2081
+ 'Text:Inside destroy insertion',
2082
'Text:Inside destroy layout',
2083
+ 'Text:Outside destroy insertion',
2084
'Text:Outside destroy layout',
2085
'AsyncText:Async destroy passive',
2086
'Text:Inside destroy passive',
@@ -1999,6 +2089,7 @@ describe('ReactSuspenseEffectsSemantics', () => {
2089
// Render fallback
2090
'ErrorBoundary render: catch',
2091
'Text:Error render',
2092
+ 'Text:Error create insertion',
2093
'Text:Error create layout',
2094
'Text:Error create passive',
2095
]);
@@ -2054,6 +2145,8 @@ describe('ReactSuspenseEffectsSemantics', () => {
2145
'ThrowsInWillUnmount render',
2146
'Text:Inside render',
2147
'Text:Outside render',
2148
+ 'Text:Inside create insertion',
2149
+ 'Text:Outside create insertion',
2150
'ThrowsInWillUnmount componentDidMount',
2151
'Text:Inside create layout',
2152
'Text:Outside create layout',
@@ -2092,12 +2185,18 @@ describe('ReactSuspenseEffectsSemantics', () => {
2185
'Text:Inside destroy layout',
2186
2187
// Finish the in-progress commit
2188
+ 'Text:Fallback create insertion',
2189
'Text:Fallback create layout',
2190
'Text:Fallback create passive',
2191
2192
// Destroy layout and passive effects in the errored tree.
2193
'App destroy layout',
2194
+ ...(gate(flags => flags.enableHiddenSubtreeInsertionEffectCleanup)
2195
+ ? ['Text:Inside destroy insertion']
2196
+ : []),
2197
+ 'Text:Fallback destroy insertion',
2198
'Text:Fallback destroy layout',
2199
+ 'Text:Outside destroy insertion',
2200
'Text:Outside destroy layout',
2201
'Text:Inside destroy passive',
2202
'Text:Fallback destroy passive',
@@ -2106,6 +2205,7 @@ describe('ReactSuspenseEffectsSemantics', () => {
2205
// Render fallback
2206
'ErrorBoundary render: catch',
2207
'Text:Error render',
2208
+ 'Text:Error create insertion',
2209
'Text:Error create layout',
2210
'Text:Error create passive',
2211
]);
@@ -2163,6 +2263,8 @@ describe('ReactSuspenseEffectsSemantics', () => {
2263
'ThrowsInLayoutEffect render',
2264
'Text:Inside render',
2265
'Text:Outside render',
2266
+ 'Text:Inside create insertion',
2267
+ 'Text:Outside create insertion',
2268
'ThrowsInLayoutEffect useLayoutEffect create',
2269
'Text:Inside create layout',
2270
'Text:Outside create layout',
@@ -2196,6 +2298,7 @@ describe('ReactSuspenseEffectsSemantics', () => {
2298
'Text:Outside render',
2299
'ThrowsInLayoutEffect useLayoutEffect destroy',
2300
'Text:Inside destroy layout',
2301
+ 'Text:Fallback create insertion',
2302
'Text:Fallback create layout',
2303
'Text:Fallback create passive',
2304
@@ -2226,6 +2329,7 @@ describe('ReactSuspenseEffectsSemantics', () => {
2329
'ThrowsInLayoutEffect render',
2330
'Text:Inside render',
2331
2332
+ 'Text:Fallback destroy insertion',
2333
'Text:Fallback destroy layout',
2334
2335
// Even though an error was thrown in useLayoutEffect,
@@ -2241,7 +2345,9 @@ describe('ReactSuspenseEffectsSemantics', () => {
2345
// Destroy layout and passive effects in the errored tree.
2346
'App destroy layout',
2347
'AsyncText:Async destroy layout',
2348
+ 'Text:Inside destroy insertion',
2349
'Text:Inside destroy layout',
2350
+ 'Text:Outside destroy insertion',
2351
'Text:Outside destroy layout',
2352
'AsyncText:Async destroy passive',
2353
'Text:Inside destroy passive',
@@ -2250,6 +2356,7 @@ describe('ReactSuspenseEffectsSemantics', () => {
2356
// Render fallback
2357
'ErrorBoundary render: catch',
2358
'Text:Error render',
2359
+ 'Text:Error create insertion',
2360
'Text:Error create layout',
2361
'Text:Error create passive',
2362
]);
@@ -2305,6 +2412,8 @@ describe('ReactSuspenseEffectsSemantics', () => {
2412
'ThrowsInLayoutEffectDestroy render',
2413
'Text:Inside render',
2414
'Text:Outside render',
2415
+ 'Text:Inside create insertion',
2416
+ 'Text:Outside create insertion',
2417
'ThrowsInLayoutEffectDestroy useLayoutEffect create',
2418
'Text:Inside create layout',
2419
'Text:Outside create layout',
@@ -2343,12 +2452,18 @@ describe('ReactSuspenseEffectsSemantics', () => {
2452
'Text:Inside destroy layout',
2453
2454
// Finish the in-progress commit
2455
+ 'Text:Fallback create insertion',
2456
'Text:Fallback create layout',
2457
'Text:Fallback create passive',
2458
2459
// Destroy layout and passive effects in the errored tree.
2460
'App destroy layout',
2461
+ ...(gate(flags => flags.enableHiddenSubtreeInsertionEffectCleanup)
2462
+ ? ['Text:Inside destroy insertion']
2463
+ : []),
2464
+ 'Text:Fallback destroy insertion',
2465
'Text:Fallback destroy layout',
2466
+ 'Text:Outside destroy insertion',
2467
'Text:Outside destroy layout',
2468
'Text:Inside destroy passive',
2469
'Text:Fallback destroy passive',
@@ -2357,6 +2472,7 @@ describe('ReactSuspenseEffectsSemantics', () => {
2472
// Render fallback
2473
'ErrorBoundary render: catch',
2474
'Text:Error render',
2475
+ 'Text:Error create insertion',
2476
'Text:Error create layout',
2477
'Text:Error create passive',
2478
]);
@@ -2402,6 +2518,7 @@ describe('ReactSuspenseEffectsSemantics', () => {
2518
assertLog([
2519
'Text:Function render',
2520
'ClassText:Class render',
2521
+ 'Text:Function create insertion',
2522
'Text:Function create layout',
2523
'ClassText:Class componentDidMount',
2524
'Text:Function create passive',
@@ -2503,6 +2620,7 @@ describe('ReactSuspenseEffectsSemantics', () => {
2620
ReactNoop.render(null);
2621
});
2622
assertLog([
2623
+ 'Text:Function destroy insertion',
2624
'Text:Function destroy layout',
2625
'AsyncText:Async_1 destroy layout',
2626
'AsyncText:Async_2 destroy layout',
@@ -2562,6 +2680,7 @@ describe('ReactSuspenseEffectsSemantics', () => {
2680
'Text:Function render',
2681
'Suspender "null" render',
2682
'ClassText:Class render',
2683
+ 'Text:Function create insertion',
2684
'Text:Function create layout',
2685
'ClassText:Class componentDidMount',
2686
'Text:Function create passive',
@@ -2657,6 +2776,7 @@ describe('ReactSuspenseEffectsSemantics', () => {
2776
ReactNoop.render(null);
2777
});
2778
assertLog([
2779
+ 'Text:Function destroy insertion',
2780
'Text:Function destroy layout',
2781
'ClassText:Class componentWillUnmount',
2782
'Text:Function destroy passive',
@@ -2774,6 +2894,7 @@ describe('ReactSuspenseEffectsSemantics', () => {
2894
'ClassComponent:refCallback render',
2895
'RefCheckerInner:refCallback render',
2896
'Text:Fallback render',
2897
+ 'Text:Fallback create insertion',
2898
'Text:Fallback create layout',
2899
'Text:Fallback create passive',
2900
]);
@@ -2785,6 +2906,7 @@ describe('ReactSuspenseEffectsSemantics', () => {
2906
});
2907
assertLog([
2908
'AsyncText:Async render',
2909
+ 'Text:Fallback destroy insertion',
2910
'Text:Fallback destroy layout',
2911
'AsyncText:Async create layout',
2912
'Text:Fallback destroy passive',
@@ -2852,6 +2974,7 @@ describe('ReactSuspenseEffectsSemantics', () => {
2974
'RefCheckerInner:refObject destroy layout ref? false',
2975
'RefCheckerOuter refCallback value? false',
2976
'RefCheckerInner:refCallback destroy layout ref? false',
2977
+ 'Text:Fallback create insertion',
2978
'Text:Fallback create layout',
2979
'Text:Fallback create passive',
2980
@@ -2881,6 +3004,7 @@ describe('ReactSuspenseEffectsSemantics', () => {
3004
'RefCheckerOuter render',
3005
'RefCheckerInner:refObject render',
3006
'RefCheckerInner:refCallback render',
3007
+ 'Text:Fallback destroy insertion',
3008
'Text:Fallback destroy layout',
3009
'AsyncText:Async create layout',
3010
'RefCheckerInner:refObject create layout ref? false',
@@ -2962,6 +3086,7 @@ describe('ReactSuspenseEffectsSemantics', () => {
3086
'RefCheckerInner:refObject destroy layout ref? false',
3087
'RefCheckerOuter refCallback value? false',
3088
'RefCheckerInner:refCallback destroy layout ref? false',
3089
+ 'Text:Fallback create insertion',
3090
'Text:Fallback create layout',
3091
'Text:Fallback create passive',
3092
@@ -2989,6 +3114,7 @@ describe('ReactSuspenseEffectsSemantics', () => {
3114
'RefCheckerInner:refObject render',
3115
'ClassComponent:refCallback render',
3116
'RefCheckerInner:refCallback render',
3117
+ 'Text:Fallback destroy insertion',
3118
'Text:Fallback destroy layout',
3119
'AsyncText:Async create layout',
3120
'RefCheckerInner:refObject create layout ref? false',
@@ -3070,6 +3196,7 @@ describe('ReactSuspenseEffectsSemantics', () => {
3196
'RefCheckerInner:refObject destroy layout ref? false',
3197
'RefCheckerOuter refCallback value? false',
3198
'RefCheckerInner:refCallback destroy layout ref? false',
3199
+ 'Text:Fallback create insertion',
3200
'Text:Fallback create layout',
3201
'Text:Fallback create passive',
3202
@@ -3097,6 +3224,7 @@ describe('ReactSuspenseEffectsSemantics', () => {
3224
'RefCheckerInner:refObject render',
3225
'FunctionComponent render',
3226
'RefCheckerInner:refCallback render',
3227
+ 'Text:Fallback destroy insertion',
3228
'Text:Fallback destroy layout',
3229
'AsyncText:Async create layout',
3230
'RefCheckerInner:refObject create layout ref? false',
@@ -3180,6 +3308,7 @@ describe('ReactSuspenseEffectsSemantics', () => {
3308
'Suspend:Async',
3309
'Text:Fallback render',
3310
'RefChecker destroy layout ref? true',
3311
+ 'Text:Fallback create insertion',
3312
'Text:Fallback create layout',
3313
'Text:Fallback create passive',
3314
@@ -3196,6 +3325,7 @@ describe('ReactSuspenseEffectsSemantics', () => {
3325
assertLog([
3326
'AsyncText:Async render',
3327
'RefChecker render',
3328
+ 'Text:Fallback destroy insertion',
3329
'Text:Fallback destroy layout',
3330
'AsyncText:Async create layout',
3331
'RefChecker create layout ref? true',
@@ -3265,6 +3395,8 @@ describe('ReactSuspenseEffectsSemantics', () => {
3395
'ThrowsInRefCallback render',
3396
'Text:Inside render',
3397
'Text:Outside render',
3398
+ 'Text:Inside create insertion',
3399
+ 'Text:Outside create insertion',
3400
'ThrowsInRefCallback refCallback ref? true',
3401
'Text:Inside create layout',
3402
'Text:Outside create layout',
@@ -3298,6 +3430,7 @@ describe('ReactSuspenseEffectsSemantics', () => {
3430
'Text:Outside render',
3431
'ThrowsInRefCallback refCallback ref? false',
3432
'Text:Inside destroy layout',
3433
+ 'Text:Fallback create insertion',
3434
'Text:Fallback create layout',
3435
'Text:Fallback create passive',
3436
@@ -3330,6 +3463,7 @@ describe('ReactSuspenseEffectsSemantics', () => {
3463
3464
// Even though an error was thrown in refCallback,
3465
// subsequent layout effects should still be created.
3466
+ 'Text:Fallback destroy insertion',
3467
'Text:Fallback destroy layout',
3468
'AsyncText:Async create layout',
3469
'ThrowsInRefCallback refCallback ref? true',
@@ -3339,11 +3473,13 @@ describe('ReactSuspenseEffectsSemantics', () => {
3473
'Text:Fallback destroy passive',
3474
'AsyncText:Async create passive',
3475
3342
- // Destroy layout and passive effects in the errored tree.
3476
+ // Destroy insertion, layout, and passive effects in the errored tree.
3477
'App destroy layout',
3478
'AsyncText:Async destroy layout',
3479
'ThrowsInRefCallback refCallback ref? false',
3480
+ 'Text:Inside destroy insertion',
3481
'Text:Inside destroy layout',
3482
+ 'Text:Outside destroy insertion',
3483
'Text:Outside destroy layout',
3484
'AsyncText:Async destroy passive',
3485
'Text:Inside destroy passive',
@@ -3352,6 +3488,7 @@ describe('ReactSuspenseEffectsSemantics', () => {
3488
// Render fallback
3489
'ErrorBoundary render: catch',
3490
'Text:Error render',
3491
+ 'Text:Error create insertion',
3492
'Text:Error create layout',
3493
'Text:Error create passive',
3494
]);
packages/shared/ReactFeatureFlags.js
+5
@@ -172,6 +172,11 @@ export const transitionLaneExpirationMs = 5000;
172
// Renames the internal symbol for elements since they have changed signature/constructor
173
export const renameElementSymbol = true;
174
175
+/**
176
+ * Enables a fix to run insertion effect cleanup on hidden subtrees.
177
+ */
178
+export const enableHiddenSubtreeInsertionEffectCleanup = false;
179
+
180
/**
181
* Removes legacy style context defined using static `contextTypes` and consumed with static `childContextTypes`.
182
*/
packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js
+1
@@ -20,6 +20,7 @@
20
export const alwaysThrottleRetries = __VARIANT__;
21
export const enableAddPropertiesFastPath = __VARIANT__;
22
export const enableObjectFiber = __VARIANT__;
23
+export const enableHiddenSubtreeInsertionEffectCleanup = __VARIANT__;
24
export const enablePersistedModeClonedFlag = __VARIANT__;
25
export const enableShallowPropDiffing = __VARIANT__;
26
export const passChildrenWhenCloningPersistedNodes = __VARIANT__;
packages/shared/forks/ReactFeatureFlags.native-fb.js
+1
@@ -22,6 +22,7 @@ export const {
22
alwaysThrottleRetries,
23
enableAddPropertiesFastPath,
24
enableFabricCompleteRootInCommitPhase,
25
+ enableHiddenSubtreeInsertionEffectCleanup,
26
enableObjectFiber,
27
enablePersistedModeClonedFlag,
28
enableShallowPropDiffing,
packages/shared/forks/ReactFeatureFlags.native-oss.js
+1
@@ -50,6 +50,7 @@ export const enableFizzExternalRuntime = true;
50
export const enableFlightReadableStream = true;
51
export const enableGetInspectorDataForInstanceInProduction = false;
52
export const enableHalt = false;
53
+export const enableHiddenSubtreeInsertionEffectCleanup = false;
54
export const enableInfiniteRenderLoopDetection = true;
55
export const enableLazyContextPropagation = false;
56
export const enableContextProfiling = false;
packages/shared/forks/ReactFeatureFlags.test-renderer.js
+1
@@ -46,6 +46,7 @@ export const enableLegacyFBSupport = false;
46
export const enableFilterEmptyStringAttributesDOM = true;
47
export const enableGetInspectorDataForInstanceInProduction = false;
48
export const enableFabricCompleteRootInCommitPhase = false;
49
+export const enableHiddenSubtreeInsertionEffectCleanup = false;
50
51
export const enableRetryLaneExpiration = false;
52
export const retryLaneExpirationMs = 5000;
packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js
+1
@@ -44,6 +44,7 @@ export const enableHalt = false;
44
export const enableInfiniteRenderLoopDetection = true;
45
export const enableLazyContextPropagation = false;
46
export const enableContextProfiling = false;
47
+export const enableHiddenSubtreeInsertionEffectCleanup = true;
48
export const enableLegacyCache = false;
49
export const enableLegacyFBSupport = false;
50
export const enableLegacyHidden = false;
packages/shared/forks/ReactFeatureFlags.test-renderer.www.js
+1
@@ -49,6 +49,7 @@ export const enableFilterEmptyStringAttributesDOM = true;
49
export const enableGetInspectorDataForInstanceInProduction = false;
50
export const enableRenderableContext = false;
51
export const enableFabricCompleteRootInCommitPhase = false;
52
+export const enableHiddenSubtreeInsertionEffectCleanup = true;
53
54
export const enableRetryLaneExpiration = false;
55
export const retryLaneExpirationMs = 5000;
packages/shared/forks/ReactFeatureFlags.www-dynamic.js
+1
@@ -21,6 +21,7 @@ export const disableSchedulerTimeoutInWorkLoop = __VARIANT__;
21
export const enableAddPropertiesFastPath = __VARIANT__;
22
export const enableDeferRootSchedulingToMicrotask = __VARIANT__;
23
export const enableDO_NOT_USE_disableStrictPassiveEffect = __VARIANT__;
24
+export const enableHiddenSubtreeInsertionEffectCleanup = __VARIANT__;
25
export const enableNoCloningMemoCache = __VARIANT__;
26
export const enableObjectFiber = __VARIANT__;
27
export const enableRenderableContext = __VARIANT__;
packages/shared/forks/ReactFeatureFlags.www.js
+1
@@ -30,6 +30,7 @@ export const {
30
enableRetryLaneExpiration,
31
enableTransitionTracing,
32
enableTrustedTypesIntegration,
33
+ enableHiddenSubtreeInsertionEffectCleanup,
34
favorSafetyOverHydrationPerf,
35
renameElementSymbol,
36
retryLaneExpirationMs,