Skip to content

Commit 8066dbe

Browse files
committed
Detach sibling pointers in old child list
When a fiber is deleted, it's still part of the previous (alternate) parent fiber's list of children. Because children are a linked list, an earlier sibling that's still alive will be connected to the deleted fiber via its alternate: live fiber --alternate--> previous live fiber --sibling--> deleted fiber We can't disconnect `alternate` on nodes that haven't been deleted yet, but we can disconnect the `sibling` and `child` pointers. Will use this feature flag to test the memory impact.
1 parent 6d3ecb7 commit 8066dbe

12 files changed

+67
-0
lines changed

packages/react-reconciler/src/ReactFiberCommitWork.new.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import {
3535
enableSuspenseCallback,
3636
enableScopeAPI,
3737
enableStrictEffects,
38+
enableDetachOldChildList,
3839
} from 'shared/ReactFeatureFlags';
3940
import {
4041
FunctionComponent,
@@ -2316,6 +2317,33 @@ function commitPassiveUnmountEffects_begin() {
23162317
detachFiberAfterEffects(alternate);
23172318
}
23182319
}
2320+
2321+
if (enableDetachOldChildList) {
2322+
// A fiber was deleted from this parent fiber, but it's still part of
2323+
// the previous (alternate) parent fiber's list of children. Because
2324+
// children are a linked list, an earlier sibling that's still alive
2325+
// will be connected to the deleted fiber via its `alternate`:
2326+
//
2327+
// live fiber
2328+
// --alternate--> previous live fiber
2329+
// --sibling--> deleted fiber
2330+
//
2331+
// We can't disconnect `alternate` on nodes that haven't been deleted
2332+
// yet, but we can disconnect the `sibling` and `child` pointers.
2333+
const previousFiber = fiber.alternate;
2334+
if (previousFiber !== null) {
2335+
let detachedChild = previousFiber.child;
2336+
if (detachedChild !== null) {
2337+
previousFiber.child = null;
2338+
do {
2339+
const detachedSibling = detachedChild.sibling;
2340+
detachedChild.sibling = null;
2341+
detachedChild = detachedSibling;
2342+
} while (detachedChild !== null);
2343+
}
2344+
}
2345+
}
2346+
23192347
nextEffect = fiber;
23202348
}
23212349
}

packages/react-reconciler/src/ReactFiberCommitWork.old.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import {
3535
enableSuspenseCallback,
3636
enableScopeAPI,
3737
enableStrictEffects,
38+
enableDetachOldChildList,
3839
} from 'shared/ReactFeatureFlags';
3940
import {
4041
FunctionComponent,
@@ -2316,6 +2317,33 @@ function commitPassiveUnmountEffects_begin() {
23162317
detachFiberAfterEffects(alternate);
23172318
}
23182319
}
2320+
2321+
if (enableDetachOldChildList) {
2322+
// A fiber was deleted from this parent fiber, but it's still part of
2323+
// the previous (alternate) parent fiber's list of children. Because
2324+
// children are a linked list, an earlier sibling that's still alive
2325+
// will be connected to the deleted fiber via its `alternate`:
2326+
//
2327+
// live fiber
2328+
// --alternate--> previous live fiber
2329+
// --sibling--> deleted fiber
2330+
//
2331+
// We can't disconnect `alternate` on nodes that haven't been deleted
2332+
// yet, but we can disconnect the `sibling` and `child` pointers.
2333+
const previousFiber = fiber.alternate;
2334+
if (previousFiber !== null) {
2335+
let detachedChild = previousFiber.child;
2336+
if (detachedChild !== null) {
2337+
previousFiber.child = null;
2338+
do {
2339+
const detachedSibling = detachedChild.sibling;
2340+
detachedChild.sibling = null;
2341+
detachedChild = detachedSibling;
2342+
} while (detachedChild !== null);
2343+
}
2344+
}
2345+
}
2346+
23192347
nextEffect = fiber;
23202348
}
23212349
}

packages/shared/ReactFeatureFlags.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,8 @@ export const disableNativeComponentFrames = false;
112112
// If there are no still-mounted boundaries, the errors should be rethrown.
113113
export const skipUnmountedBoundaries = false;
114114

115+
export const enableDetachOldChildList = false;
116+
115117
// --------------------------
116118
// Future APIs to be deprecated
117119
// --------------------------

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ export const enableLegacyFBSupport = false;
4646
export const enableFilterEmptyStringAttributesDOM = false;
4747
export const disableNativeComponentFrames = false;
4848
export const skipUnmountedBoundaries = false;
49+
export const enableDetachOldChildList = false;
4950

5051
export const enableNewReconciler = false;
5152
export const deferRenderPhaseUpdateToNextBatch = true;

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ export const enableLegacyFBSupport = false;
4545
export const enableFilterEmptyStringAttributesDOM = false;
4646
export const disableNativeComponentFrames = false;
4747
export const skipUnmountedBoundaries = false;
48+
export const enableDetachOldChildList = false;
4849

4950
export const enableNewReconciler = false;
5051
export const deferRenderPhaseUpdateToNextBatch = true;

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ export const enableLegacyFBSupport = false;
4545
export const enableFilterEmptyStringAttributesDOM = false;
4646
export const disableNativeComponentFrames = false;
4747
export const skipUnmountedBoundaries = false;
48+
export const enableDetachOldChildList = false;
4849

4950
export const enableNewReconciler = false;
5051
export const deferRenderPhaseUpdateToNextBatch = true;

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ export const enableLegacyFBSupport = false;
4545
export const enableFilterEmptyStringAttributesDOM = false;
4646
export const disableNativeComponentFrames = false;
4747
export const skipUnmountedBoundaries = false;
48+
export const enableDetachOldChildList = false;
4849

4950
export const enableNewReconciler = false;
5051
export const deferRenderPhaseUpdateToNextBatch = true;

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ export const enableLegacyFBSupport = false;
4545
export const enableFilterEmptyStringAttributesDOM = false;
4646
export const disableNativeComponentFrames = false;
4747
export const skipUnmountedBoundaries = false;
48+
export const enableDetachOldChildList = false;
4849

4950
export const enableNewReconciler = false;
5051
export const deferRenderPhaseUpdateToNextBatch = true;

packages/shared/forks/ReactFeatureFlags.testing.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ export const enableLegacyFBSupport = false;
4545
export const enableFilterEmptyStringAttributesDOM = false;
4646
export const disableNativeComponentFrames = false;
4747
export const skipUnmountedBoundaries = false;
48+
export const enableDetachOldChildList = false;
4849

4950
export const enableNewReconciler = false;
5051
export const deferRenderPhaseUpdateToNextBatch = true;

packages/shared/forks/ReactFeatureFlags.testing.www.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ export const enableLegacyFBSupport = !__EXPERIMENTAL__;
4545
export const enableFilterEmptyStringAttributesDOM = false;
4646
export const disableNativeComponentFrames = false;
4747
export const skipUnmountedBoundaries = true;
48+
export const enableDetachOldChildList = false;
4849

4950
export const enableNewReconciler = false;
5051
export const deferRenderPhaseUpdateToNextBatch = true;

0 commit comments

Comments
 (0)