diff --git a/packages/react-reconciler/src/ReactFiberCommitWork.js b/packages/react-reconciler/src/ReactFiberCommitWork.js index 740e76509503..d11c381c89c8 100644 --- a/packages/react-reconciler/src/ReactFiberCommitWork.js +++ b/packages/react-reconciler/src/ReactFiberCommitWork.js @@ -730,11 +730,11 @@ function commitUnmount(current: Fiber): void { if (typeof instance.componentWillUnmount === 'function') { safelyCallComponentWillUnmount(current, instance); } - return; + break; } case HostComponent: { safelyDetachRef(current); - return; + break; } case HostPortal: { // TODO: this is recursive. @@ -745,7 +745,7 @@ function commitUnmount(current: Fiber): void { } else if (supportsPersistence) { emptyPortalContainer(current); } - return; + break; } case EventComponent: { if (enableEventAPI) { @@ -756,6 +756,12 @@ function commitUnmount(current: Fiber): void { } } } + + // Remove reference for GC + current.stateNode = null; + if (current.alternate != null) { + current.alternate.stateNode = null; + } } function commitNestedUnmounts(root: Fiber): void { @@ -1050,19 +1056,15 @@ function unmountHostComponents(current): void { } if (node.tag === HostComponent || node.tag === HostText) { + // Save stateNode reference so commitUnmount can clear it. + const stateNode: Instance | TextInstance = node.stateNode; commitNestedUnmounts(node); // After all the children have unmounted, it is now safe to remove the // node from the tree. if (currentParentIsContainer) { - removeChildFromContainer( - ((currentParent: any): Container), - (node.stateNode: Instance | TextInstance), - ); + removeChildFromContainer(((currentParent: any): Container), stateNode); } else { - removeChild( - ((currentParent: any): Instance), - (node.stateNode: Instance | TextInstance), - ); + removeChild(((currentParent: any): Instance), stateNode); } // Don't visit children because we already visited them. } else if ( diff --git a/packages/react-reconciler/src/ReactFiberScheduler.new.js b/packages/react-reconciler/src/ReactFiberScheduler.new.js index c86bd58ce6a5..129ec2abaa0f 100644 --- a/packages/react-reconciler/src/ReactFiberScheduler.new.js +++ b/packages/react-reconciler/src/ReactFiberScheduler.new.js @@ -1404,6 +1404,15 @@ function commitRootImpl(root, expirationTime) { rootWithPendingPassiveEffects = root; pendingPassiveEffectsExpirationTime = expirationTime; } else { + // We are done with the effect chain at this point so let's clear the + // nextEffect pointers to assist with GC. If we have passive effects, we'll + // clear this in flushPassiveEffects. + nextEffect = firstEffect; + while (nextEffect !== null) { + const nextNextEffect = nextEffect.nextEffect; + nextEffect.nextEffect = null; + nextEffect = nextNextEffect; + } if (enableSchedulerTracing) { // If there are no passive effects, then we can complete the pending // interactions. Otherwise, we'll wait until after the passive effects @@ -1620,7 +1629,10 @@ export function flushPassiveEffects() { captureCommitPhaseError(effect, error); } } - effect = effect.nextEffect; + const nextNextEffect = effect.nextEffect; + // Remove nextEffect pointer to assist GC + effect.nextEffect = null; + effect = nextNextEffect; } if (enableSchedulerTracing) { diff --git a/packages/react-reconciler/src/ReactFiberScheduler.old.js b/packages/react-reconciler/src/ReactFiberScheduler.old.js index 965eaa1cdc62..f1a6fa469136 100644 --- a/packages/react-reconciler/src/ReactFiberScheduler.old.js +++ b/packages/react-reconciler/src/ReactFiberScheduler.old.js @@ -574,7 +574,10 @@ function commitPassiveEffects(root: FiberRoot, firstEffect: Fiber): void { captureCommitPhaseError(effect, error); } } - effect = effect.nextEffect; + const nextNextEffect = effect.nextEffect; + // Remove nextEffect pointer to assist GC + effect.nextEffect = null; + effect = nextNextEffect; } while (effect !== null); if (__DEV__) { resetCurrentFiber(); @@ -831,6 +834,16 @@ function commitRoot(root: FiberRoot, finishedWork: Fiber): void { } passiveEffectCallbackHandle = scheduleCallback(NormalPriority, callback); passiveEffectCallback = callback; + } else { + // We are done with the effect chain at this point so let's clear the + // nextEffect pointers to assist with GC. If we have passive effects, we'll + // clear this in commitPassiveEffects. + nextEffect = firstEffect; + while (nextEffect !== null) { + const nextNextEffect = nextEffect.nextEffect; + nextEffect.nextEffect = null; + nextEffect = nextNextEffect; + } } isCommitting = false;