Skip to content

Commit f081a4b

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 82c7916 commit f081a4b

13 files changed

Lines changed: 203 additions & 262 deletions

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

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import {
3636
enableScopeAPI,
3737
enableStrictEffects,
3838
enableStrongMemoryCleanup,
39+
enableDetachOldChildList,
3940
} from 'shared/ReactFeatureFlags';
4041
import {
4142
FunctionComponent,
@@ -2323,6 +2324,33 @@ function commitPassiveUnmountEffects_begin() {
23232324
detachFiberAfterEffects(alternate);
23242325
}
23252326
}
2327+
2328+
if (enableDetachOldChildList) {
2329+
// A fiber was deleted from this parent fiber, but it's still part of
2330+
// the previous (alternate) parent fiber's list of children. Because
2331+
// children are a linked list, an earlier sibling that's still alive
2332+
// will be connected to the deleted fiber via its `alternate`:
2333+
//
2334+
// live fiber
2335+
// --alternate--> previous live fiber
2336+
// --sibling--> deleted fiber
2337+
//
2338+
// We can't disconnect `alternate` on nodes that haven't been deleted
2339+
// yet, but we can disconnect the `sibling` and `child` pointers.
2340+
const previousFiber = fiber.alternate;
2341+
if (previousFiber !== null) {
2342+
let detachedChild = previousFiber.child;
2343+
if (detachedChild !== null) {
2344+
previousFiber.child = null;
2345+
do {
2346+
const detachedSibling = detachedChild.sibling;
2347+
detachedChild.sibling = null;
2348+
detachedChild = detachedSibling;
2349+
} while (detachedChild !== null);
2350+
}
2351+
}
2352+
}
2353+
23262354
nextEffect = fiber;
23272355
}
23282356
}

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

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import {
3636
enableScopeAPI,
3737
enableStrictEffects,
3838
enableStrongMemoryCleanup,
39+
enableDetachOldChildList,
3940
} from 'shared/ReactFeatureFlags';
4041
import {
4142
FunctionComponent,
@@ -2323,6 +2324,33 @@ function commitPassiveUnmountEffects_begin() {
23232324
detachFiberAfterEffects(alternate);
23242325
}
23252326
}
2327+
2328+
if (enableDetachOldChildList) {
2329+
// A fiber was deleted from this parent fiber, but it's still part of
2330+
// the previous (alternate) parent fiber's list of children. Because
2331+
// children are a linked list, an earlier sibling that's still alive
2332+
// will be connected to the deleted fiber via its `alternate`:
2333+
//
2334+
// live fiber
2335+
// --alternate--> previous live fiber
2336+
// --sibling--> deleted fiber
2337+
//
2338+
// We can't disconnect `alternate` on nodes that haven't been deleted
2339+
// yet, but we can disconnect the `sibling` and `child` pointers.
2340+
const previousFiber = fiber.alternate;
2341+
if (previousFiber !== null) {
2342+
let detachedChild = previousFiber.child;
2343+
if (detachedChild !== null) {
2344+
previousFiber.child = null;
2345+
do {
2346+
const detachedSibling = detachedChild.sibling;
2347+
detachedChild.sibling = null;
2348+
detachedChild = detachedSibling;
2349+
} while (detachedChild !== null);
2350+
}
2351+
}
2352+
}
2353+
23262354
nextEffect = fiber;
23272355
}
23282356
}

0 commit comments

Comments
 (0)