diff --git a/packages/react-reconciler/src/ReactFiberCommitWork.new.js b/packages/react-reconciler/src/ReactFiberCommitWork.new.js index 7985366d3f67c..cc15aa0f2e996 100644 --- a/packages/react-reconciler/src/ReactFiberCommitWork.new.js +++ b/packages/react-reconciler/src/ReactFiberCommitWork.new.js @@ -35,6 +35,7 @@ import { enableSuspenseCallback, enableScopeAPI, enableStrictEffects, + enableStrongMemoryCleanup, } from 'shared/ReactFeatureFlags'; import { FunctionComponent, @@ -1212,9 +1213,28 @@ function detachFiberMutation(fiber: Fiber) { fiber.return = null; } -export function detachFiberAfterEffects(fiber: Fiber): void { +export function detachFiberAfterEffects( + fiber: Fiber, + recurseIntoSibbling: ?boolean, +): void { // Null out fields to improve GC for references that may be lingering (e.g. DevTools). // Note that we already cleared the return pointer in detachFiberMutation(). + if (enableStrongMemoryCleanup) { + if (fiber.child) { + detachFiberAfterEffects(fiber.child, true); + } + if (fiber.sibling && recurseIntoSibbling === true) { + detachFiberAfterEffects(fiber.sibling, true); + } + if (fiber.stateNode) { + Object.keys(fiber.stateNode).forEach(key => { + if (key.indexOf('__react') === 0) { + delete fiber.stateNode[key]; + } + }); + } + fiber.return = null; + } fiber.alternate = null; fiber.child = null; fiber.deletions = null; diff --git a/packages/react-reconciler/src/ReactFiberCommitWork.old.js b/packages/react-reconciler/src/ReactFiberCommitWork.old.js index d50095b3bebb1..78dee1e928a50 100644 --- a/packages/react-reconciler/src/ReactFiberCommitWork.old.js +++ b/packages/react-reconciler/src/ReactFiberCommitWork.old.js @@ -35,6 +35,7 @@ import { enableSuspenseCallback, enableScopeAPI, enableStrictEffects, + enableStrongMemoryCleanup, } from 'shared/ReactFeatureFlags'; import { FunctionComponent, @@ -1212,9 +1213,28 @@ function detachFiberMutation(fiber: Fiber) { fiber.return = null; } -export function detachFiberAfterEffects(fiber: Fiber): void { +export function detachFiberAfterEffects( + fiber: Fiber, + recurseIntoSibbling: ?boolean, +): void { // Null out fields to improve GC for references that may be lingering (e.g. DevTools). // Note that we already cleared the return pointer in detachFiberMutation(). + if (enableStrongMemoryCleanup) { + if (fiber.child) { + detachFiberAfterEffects(fiber.child, true); + } + if (fiber.sibling && recurseIntoSibbling === true) { + detachFiberAfterEffects(fiber.sibling, true); + } + if (fiber.stateNode) { + Object.keys(fiber.stateNode).forEach(key => { + if (key.indexOf('__react') === 0) { + delete fiber.stateNode[key]; + } + }); + } + fiber.return = null; + } fiber.alternate = null; fiber.child = null; fiber.deletions = null; diff --git a/packages/shared/ReactFeatureFlags.js b/packages/shared/ReactFeatureFlags.js index 75ab4b6842d90..c697dbccb2050 100644 --- a/packages/shared/ReactFeatureFlags.js +++ b/packages/shared/ReactFeatureFlags.js @@ -112,6 +112,8 @@ export const disableNativeComponentFrames = false; // If there are no still-mounted boundaries, the errors should be rethrown. export const skipUnmountedBoundaries = false; +export const enableStrongMemoryCleanup = true; + // -------------------------- // Future APIs to be deprecated // -------------------------- diff --git a/packages/shared/forks/ReactFeatureFlags.native-fb.js b/packages/shared/forks/ReactFeatureFlags.native-fb.js index b6a8016ec8b77..05eff8ba505f3 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-fb.js +++ b/packages/shared/forks/ReactFeatureFlags.native-fb.js @@ -46,6 +46,7 @@ export const enableLegacyFBSupport = false; export const enableFilterEmptyStringAttributesDOM = false; export const disableNativeComponentFrames = false; export const skipUnmountedBoundaries = false; +export const enableStrongMemoryCleanup = true; export const enableNewReconciler = false; export const deferRenderPhaseUpdateToNextBatch = true; diff --git a/packages/shared/forks/ReactFeatureFlags.native-oss.js b/packages/shared/forks/ReactFeatureFlags.native-oss.js index cb8721af25fe9..6b3f25798bd58 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-oss.js +++ b/packages/shared/forks/ReactFeatureFlags.native-oss.js @@ -45,6 +45,7 @@ export const enableLegacyFBSupport = false; export const enableFilterEmptyStringAttributesDOM = false; export const disableNativeComponentFrames = false; export const skipUnmountedBoundaries = false; +export const enableStrongMemoryCleanup = true; export const enableNewReconciler = false; export const deferRenderPhaseUpdateToNextBatch = true; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.js index b504491d98de2..97199b982ddd8 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.js @@ -45,6 +45,7 @@ export const enableLegacyFBSupport = false; export const enableFilterEmptyStringAttributesDOM = false; export const disableNativeComponentFrames = false; export const skipUnmountedBoundaries = false; +export const enableStrongMemoryCleanup = true; export const enableNewReconciler = false; export const deferRenderPhaseUpdateToNextBatch = true; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js index 7098bfed2aa5b..d5234f84109ac 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js @@ -45,6 +45,7 @@ export const enableLegacyFBSupport = false; export const enableFilterEmptyStringAttributesDOM = false; export const disableNativeComponentFrames = false; export const skipUnmountedBoundaries = false; +export const enableStrongMemoryCleanup = true; export const enableNewReconciler = false; export const deferRenderPhaseUpdateToNextBatch = true; diff --git a/packages/shared/forks/ReactFeatureFlags.testing.js b/packages/shared/forks/ReactFeatureFlags.testing.js index a321f5ea12f92..0ad3c240c971b 100644 --- a/packages/shared/forks/ReactFeatureFlags.testing.js +++ b/packages/shared/forks/ReactFeatureFlags.testing.js @@ -45,6 +45,7 @@ export const enableLegacyFBSupport = false; export const enableFilterEmptyStringAttributesDOM = false; export const disableNativeComponentFrames = false; export const skipUnmountedBoundaries = false; +export const enableStrongMemoryCleanup = true; export const enableNewReconciler = false; export const deferRenderPhaseUpdateToNextBatch = true; diff --git a/packages/shared/forks/ReactFeatureFlags.testing.www.js b/packages/shared/forks/ReactFeatureFlags.testing.www.js index bb6a952355657..2da6498824a56 100644 --- a/packages/shared/forks/ReactFeatureFlags.testing.www.js +++ b/packages/shared/forks/ReactFeatureFlags.testing.www.js @@ -45,6 +45,7 @@ export const enableLegacyFBSupport = !__EXPERIMENTAL__; export const enableFilterEmptyStringAttributesDOM = false; export const disableNativeComponentFrames = false; export const skipUnmountedBoundaries = true; +export const enableStrongMemoryCleanup = true; export const enableNewReconciler = false; export const deferRenderPhaseUpdateToNextBatch = true; diff --git a/packages/shared/forks/ReactFeatureFlags.www.js b/packages/shared/forks/ReactFeatureFlags.www.js index 893c2699b0d07..12a00a17fcf62 100644 --- a/packages/shared/forks/ReactFeatureFlags.www.js +++ b/packages/shared/forks/ReactFeatureFlags.www.js @@ -92,6 +92,8 @@ export const enableNewReconciler = __VARIANT__; export const enableRecursiveCommitTraversal = false; +export const enableStrongMemoryCleanup = __VARIANT__; + // Flow magic to verify the exports of this file match the original version. // eslint-disable-next-line no-unused-vars type Check<_X, Y: _X, X: Y = _X> = null;