From 8319220d99a07c9083f8ec63f5e53e3ba1d6793e Mon Sep 17 00:00:00 2001 From: paulshen Date: Mon, 2 Aug 2021 17:47:38 -0600 Subject: [PATCH 1/3] clear stateNode https://github.com/discord/react/commit/d28ee4881f8b30537d6cb3d0bf6725078d4c1ad7 --- .../src/ReactFiberCommitWork.new.js | 32 ++++++++++--------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/packages/react-reconciler/src/ReactFiberCommitWork.new.js b/packages/react-reconciler/src/ReactFiberCommitWork.new.js index 4e9acfae11356..cd0282c7ff807 100644 --- a/packages/react-reconciler/src/ReactFiberCommitWork.new.js +++ b/packages/react-reconciler/src/ReactFiberCommitWork.new.js @@ -1044,7 +1044,7 @@ function commitUnmount( } while (effect !== firstEffect); } } - return; + break; } case ClassComponent: { safelyDetachRef(current, nearestMountedAncestor); @@ -1056,11 +1056,11 @@ function commitUnmount( nearestMountedAncestor, ); } - return; + break; } case HostComponent: { safelyDetachRef(current, nearestMountedAncestor); - return; + break; } case HostPortal: { // TODO: this is recursive. @@ -1076,7 +1076,7 @@ function commitUnmount( } else if (supportsPersistence) { emptyPortalContainer(current); } - return; + break; } case FundamentalComponent: { if (enableFundamentalAPI) { @@ -1086,7 +1086,7 @@ function commitUnmount( current.stateNode = null; } } - return; + break; } case DehydratedFragment: { if (enableSuspenseCallback) { @@ -1098,15 +1098,21 @@ function commitUnmount( } } } - return; + break; } case ScopeComponent: { if (enableScopeAPI) { safelyDetachRef(current, nearestMountedAncestor); } - return; + break; } } + + // Remove reference for GC + current.stateNode = null; + if (current.alternate != null) { + current.alternate.stateNode = null; + } } function commitNestedUnmounts( @@ -1460,6 +1466,8 @@ function unmountHostComponents( } if (node.tag === HostComponent || node.tag === HostText) { + // Save stateNode reference so commitUnmount can clear it. + const stateNode: Instance | TextInstance = node.stateNode; commitNestedUnmounts( finishedRoot, node, @@ -1469,15 +1477,9 @@ function unmountHostComponents( // 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 (enableFundamentalAPI && node.tag === FundamentalComponent) { From f959042e1027b5d4e1aff72c2152e0d63f8e45ec Mon Sep 17 00:00:00 2001 From: paulshen Date: Mon, 2 Aug 2021 17:53:44 -0600 Subject: [PATCH 2/3] detach fiber from host component https://github.com/discord/react/commit/2e5ee2f8ce0fea --- .../src/client/ReactDOMComponentTree.js | 7 ++++--- .../src/ReactFiberCommitWork.new.js | 17 +++++++++++++++++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/packages/react-dom/src/client/ReactDOMComponentTree.js b/packages/react-dom/src/client/ReactDOMComponentTree.js index fbf0a81e29064..bff3273c4c8d3 100644 --- a/packages/react-dom/src/client/ReactDOMComponentTree.js +++ b/packages/react-dom/src/client/ReactDOMComponentTree.js @@ -33,9 +33,10 @@ import {getParentSuspenseInstance} from './ReactDOMHostConfig'; import invariant from 'shared/invariant'; import {enableScopeAPI} from 'shared/ReactFeatureFlags'; -const randomKey = Math.random() - .toString(36) - .slice(2); +// const randomKey = Math.random() +// .toString(36) +// .slice(2); +const randomKey = ''; const internalInstanceKey = '__reactFiber$' + randomKey; const internalPropsKey = '__reactProps$' + randomKey; const internalContainerInstanceKey = '__reactContainer$' + randomKey; diff --git a/packages/react-reconciler/src/ReactFiberCommitWork.new.js b/packages/react-reconciler/src/ReactFiberCommitWork.new.js index cd0282c7ff807..d55125670c597 100644 --- a/packages/react-reconciler/src/ReactFiberCommitWork.new.js +++ b/packages/react-reconciler/src/ReactFiberCommitWork.new.js @@ -1060,6 +1060,23 @@ function commitUnmount( } case HostComponent: { safelyDetachRef(current, nearestMountedAncestor); + // HACK: detach fiber references from DOM + current.stateNode.__reactFiber$ = null; + current.stateNode.__reactProps$ = null; + current.stateNode.__reactContainer$ = null; + current.stateNode.__reactEvents$ = null; + current.stateNode.__reactListeners$ = null; + current.stateNode.__reactHandles$ = null; + break; + } + case HostText: { + // HACK: detach fiber references from DOM + current.stateNode.__reactFiber$ = null; + current.stateNode.__reactProps$ = null; + current.stateNode.__reactContainer$ = null; + current.stateNode.__reactEvents$ = null; + current.stateNode.__reactListeners$ = null; + current.stateNode.__reactHandles$ = null; break; } case HostPortal: { From 67a1cd3e0ffa4501a37c39af19887aa02051bb28 Mon Sep 17 00:00:00 2001 From: paulshen Date: Mon, 2 Aug 2021 22:22:50 -0600 Subject: [PATCH 3/3] apply to ReactFiberCommitWork.old.js --- .../src/client/ReactDOMComponentTree.js | 1 + .../src/ReactFiberCommitWork.old.js | 49 +++++++++++++------ 2 files changed, 35 insertions(+), 15 deletions(-) diff --git a/packages/react-dom/src/client/ReactDOMComponentTree.js b/packages/react-dom/src/client/ReactDOMComponentTree.js index bff3273c4c8d3..ba72082a1706a 100644 --- a/packages/react-dom/src/client/ReactDOMComponentTree.js +++ b/packages/react-dom/src/client/ReactDOMComponentTree.js @@ -36,6 +36,7 @@ import {enableScopeAPI} from 'shared/ReactFeatureFlags'; // const randomKey = Math.random() // .toString(36) // .slice(2); +// HACK: not so random anymore const randomKey = ''; const internalInstanceKey = '__reactFiber$' + randomKey; const internalPropsKey = '__reactProps$' + randomKey; diff --git a/packages/react-reconciler/src/ReactFiberCommitWork.old.js b/packages/react-reconciler/src/ReactFiberCommitWork.old.js index e094e5bd9b5a8..6ad605ca3698b 100644 --- a/packages/react-reconciler/src/ReactFiberCommitWork.old.js +++ b/packages/react-reconciler/src/ReactFiberCommitWork.old.js @@ -906,7 +906,7 @@ function commitUnmount( } while (effect !== firstEffect); } } - return; + break; } case ClassComponent: { safelyDetachRef(current); @@ -914,11 +914,28 @@ function commitUnmount( if (typeof instance.componentWillUnmount === 'function') { safelyCallComponentWillUnmount(current, instance); } - return; + break; } case HostComponent: { safelyDetachRef(current); - return; + // HACK: detach fiber references from DOM + current.stateNode.__reactFiber$ = null; + current.stateNode.__reactProps$ = null; + current.stateNode.__reactContainer$ = null; + current.stateNode.__reactEvents$ = null; + current.stateNode.__reactListeners$ = null; + current.stateNode.__reactHandles$ = null; + break; + } + case HostText: { + // HACK: detach fiber references from DOM + current.stateNode.__reactFiber$ = null; + current.stateNode.__reactProps$ = null; + current.stateNode.__reactContainer$ = null; + current.stateNode.__reactEvents$ = null; + current.stateNode.__reactListeners$ = null; + current.stateNode.__reactHandles$ = null; + break; } case HostPortal: { // TODO: this is recursive. @@ -929,7 +946,7 @@ function commitUnmount( } else if (supportsPersistence) { emptyPortalContainer(current); } - return; + break; } case FundamentalComponent: { if (enableFundamentalAPI) { @@ -939,7 +956,7 @@ function commitUnmount( current.stateNode = null; } } - return; + break; } case DehydratedFragment: { if (enableSuspenseCallback) { @@ -951,15 +968,21 @@ function commitUnmount( } } } - return; + break; } case ScopeComponent: { if (enableScopeAPI) { safelyDetachRef(current); } - return; + break; } } + + // Remove reference for GC + current.stateNode = null; + if (current.alternate != null) { + current.alternate.stateNode = null; + } } function commitNestedUnmounts( @@ -1314,19 +1337,15 @@ function unmountHostComponents( } if (node.tag === HostComponent || node.tag === HostText) { + // Save stateNode reference so commitUnmount can clear it. + const stateNode: Instance | TextInstance = node.stateNode; commitNestedUnmounts(finishedRoot, node, renderPriorityLevel); // 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 (enableFundamentalAPI && node.tag === FundamentalComponent) {