diff --git a/packages/react-reconciler/src/ReactFiberCommitWork.new.js b/packages/react-reconciler/src/ReactFiberCommitWork.new.js index 1e19f4086e0c7..36472020c602e 100644 --- a/packages/react-reconciler/src/ReactFiberCommitWork.new.js +++ b/packages/react-reconciler/src/ReactFiberCommitWork.new.js @@ -36,6 +36,7 @@ import { enableScopeAPI, enableStrictEffects, enableStrongMemoryCleanup, + enableDetachOldChildList, } from 'shared/ReactFeatureFlags'; import { FunctionComponent, @@ -2323,6 +2324,33 @@ function commitPassiveUnmountEffects_begin() { detachFiberAfterEffects(alternate); } } + + if (enableDetachOldChildList) { + // A fiber was deleted from this parent fiber, but 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. + const previousFiber = fiber.alternate; + if (previousFiber !== null) { + let detachedChild = previousFiber.child; + if (detachedChild !== null) { + previousFiber.child = null; + do { + const detachedSibling = detachedChild.sibling; + detachedChild.sibling = null; + detachedChild = detachedSibling; + } while (detachedChild !== null); + } + } + } + nextEffect = fiber; } } diff --git a/packages/react-reconciler/src/ReactFiberCommitWork.old.js b/packages/react-reconciler/src/ReactFiberCommitWork.old.js index 8d187832e4d84..b21ded0035759 100644 --- a/packages/react-reconciler/src/ReactFiberCommitWork.old.js +++ b/packages/react-reconciler/src/ReactFiberCommitWork.old.js @@ -36,6 +36,7 @@ import { enableScopeAPI, enableStrictEffects, enableStrongMemoryCleanup, + enableDetachOldChildList, } from 'shared/ReactFeatureFlags'; import { FunctionComponent, @@ -2323,6 +2324,33 @@ function commitPassiveUnmountEffects_begin() { detachFiberAfterEffects(alternate); } } + + if (enableDetachOldChildList) { + // A fiber was deleted from this parent fiber, but 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. + const previousFiber = fiber.alternate; + if (previousFiber !== null) { + let detachedChild = previousFiber.child; + if (detachedChild !== null) { + previousFiber.child = null; + do { + const detachedSibling = detachedChild.sibling; + detachedChild.sibling = null; + detachedChild = detachedSibling; + } while (detachedChild !== null); + } + } + } + nextEffect = fiber; } } diff --git a/packages/react-reconciler/src/ReactFiberLane.new.js b/packages/react-reconciler/src/ReactFiberLane.new.js index bf5086acb9432..4e7d4fcbd146a 100644 --- a/packages/react-reconciler/src/ReactFiberLane.new.js +++ b/packages/react-reconciler/src/ReactFiberLane.new.js @@ -11,25 +11,6 @@ import type {FiberRoot, ReactPriorityLevel} from './ReactInternalTypes'; // TODO: Ideally these types would be opaque but that doesn't work well with // our reconciler fork infra, since these leak into non-reconciler packages. -export type LanePriority = - | 0 - | 1 - | 2 - | 3 - | 4 - | 5 - | 6 - | 7 - | 8 - | 9 - | 10 - | 11 - | 12 - | 13 - | 14 - | 15 - | 16 - | 17; export type Lanes = number; export type Lane = number; @@ -43,35 +24,8 @@ import { UserBlockingPriority as UserBlockingSchedulerPriority, NormalPriority as NormalSchedulerPriority, IdlePriority as IdleSchedulerPriority, - NoPriority as NoSchedulerPriority, } from './SchedulerWithReactIntegration.new'; -export const SyncLanePriority: LanePriority = 15; -export const SyncBatchedLanePriority: LanePriority = 14; - -const InputDiscreteHydrationLanePriority: LanePriority = 13; -export const InputDiscreteLanePriority: LanePriority = 12; - -const InputContinuousHydrationLanePriority: LanePriority = 11; -export const InputContinuousLanePriority: LanePriority = 10; - -const DefaultHydrationLanePriority: LanePriority = 9; -export const DefaultLanePriority: LanePriority = 8; - -const TransitionHydrationPriority: LanePriority = 7; -export const TransitionPriority: LanePriority = 6; - -const RetryLanePriority: LanePriority = 5; - -const SelectiveHydrationLanePriority: LanePriority = 4; - -const IdleHydrationLanePriority: LanePriority = 3; -export const IdleLanePriority: LanePriority = 2; - -const OffscreenLanePriority: LanePriority = 1; - -export const NoLanePriority: LanePriority = 0; - // Lane values below should be kept in sync with getLabelsForLanes(), used by react-devtools-scheduling-profiler. // If those values are changed that package should be rebuilt and redeployed. @@ -83,31 +37,30 @@ export const NoLane: Lane = /* */ 0b0000000000000000000 export const SyncLane: Lane = /* */ 0b0000000000000000000000000000001; export const SyncBatchedLane: Lane = /* */ 0b0000000000000000000000000000010; -export const InputDiscreteHydrationLane: Lane = /* */ 0b0000000000000000000000000000100; -export const InputDiscreteLane: Lanes = /* */ 0b0000000000000000000000000001000; - -const InputContinuousHydrationLane: Lane = /* */ 0b0000000000000000000000000010000; -export const InputContinuousLane: Lanes = /* */ 0b0000000000000000000000000100000; - -export const DefaultHydrationLane: Lane = /* */ 0b0000000000000000000000001000000; -export const DefaultLane: Lanes = /* */ 0b0000000000000000000000010000000; - -const TransitionHydrationLane: Lane = /* */ 0b0000000000000000000000100000000; -const TransitionLanes: Lanes = /* */ 0b0000000011111111111111000000000; -const TransitionLane1: Lane = /* */ 0b0000000000000000000001000000000; -const TransitionLane2: Lane = /* */ 0b0000000000000000000010000000000; -const TransitionLane3: Lane = /* */ 0b0000000000000000000100000000000; -const TransitionLane4: Lane = /* */ 0b0000000000000000001000000000000; -const TransitionLane5: Lane = /* */ 0b0000000000000000010000000000000; -const TransitionLane6: Lane = /* */ 0b0000000000000000100000000000000; -const TransitionLane7: Lane = /* */ 0b0000000000000001000000000000000; -const TransitionLane8: Lane = /* */ 0b0000000000000010000000000000000; -const TransitionLane9: Lane = /* */ 0b0000000000000100000000000000000; -const TransitionLane10: Lane = /* */ 0b0000000000001000000000000000000; -const TransitionLane11: Lane = /* */ 0b0000000000010000000000000000000; -const TransitionLane12: Lane = /* */ 0b0000000000100000000000000000000; -const TransitionLane13: Lane = /* */ 0b0000000001000000000000000000000; -const TransitionLane14: Lane = /* */ 0b0000000010000000000000000000000; +const InputContinuousHydrationLane: Lane = /* */ 0b0000000000000000000000000000100; +export const InputContinuousLane: Lanes = /* */ 0b0000000000000000000000000001000; + +export const DefaultHydrationLane: Lane = /* */ 0b0000000000000000000000000010000; +export const DefaultLane: Lanes = /* */ 0b0000000000000000000000000100000; + +const TransitionHydrationLane: Lane = /* */ 0b0000000000000000000000001000000; +const TransitionLanes: Lanes = /* */ 0b0000000011111111111111110000000; +const TransitionLane1: Lane = /* */ 0b0000000000000000000000010000000; +const TransitionLane2: Lane = /* */ 0b0000000000000000000000100000000; +const TransitionLane3: Lane = /* */ 0b0000000000000000000001000000000; +const TransitionLane4: Lane = /* */ 0b0000000000000000000010000000000; +const TransitionLane5: Lane = /* */ 0b0000000000000000000100000000000; +const TransitionLane6: Lane = /* */ 0b0000000000000000001000000000000; +const TransitionLane7: Lane = /* */ 0b0000000000000000010000000000000; +const TransitionLane8: Lane = /* */ 0b0000000000000000100000000000000; +const TransitionLane9: Lane = /* */ 0b0000000000000001000000000000000; +const TransitionLane10: Lane = /* */ 0b0000000000000010000000000000000; +const TransitionLane11: Lane = /* */ 0b0000000000000100000000000000000; +const TransitionLane12: Lane = /* */ 0b0000000000001000000000000000000; +const TransitionLane13: Lane = /* */ 0b0000000000010000000000000000000; +const TransitionLane14: Lane = /* */ 0b0000000000100000000000000000000; +const TransitionLane15: Lane = /* */ 0b0000000001000000000000000000000; +const TransitionLane16: Lane = /* */ 0b0000000010000000000000000000000; const RetryLanes: Lanes = /* */ 0b0000111100000000000000000000000; const RetryLane1: Lane = /* */ 0b0000000100000000000000000000000; @@ -137,12 +90,6 @@ export function getLabelsForLanes(lanes: Lanes): Array | void { if (lanes & SyncBatchedLane) { labels.push('SyncBatched'); } - if (lanes & InputDiscreteHydrationLane) { - labels.push('InputDiscreteHydration'); - } - if (lanes & InputDiscreteLane) { - labels.push('InputDiscrete'); - } if (lanes & InputContinuousHydrationLane) { labels.push('InputContinuousHydration'); } @@ -182,52 +129,42 @@ export function getLabelsForLanes(lanes: Lanes): Array | void { export const NoTimestamp = -1; -let currentUpdateLanePriority: LanePriority = NoLanePriority; +let currentUpdateLane: Lane = NoLane; let nextTransitionLane: Lane = TransitionLane1; let nextRetryLane: Lane = RetryLane1; -export function getCurrentUpdateLanePriority(): LanePriority { - return currentUpdateLanePriority; +export function getCurrentUpdateLane(): Lane { + return currentUpdateLane; } -export function setCurrentUpdateLanePriority(newLanePriority: LanePriority) { - currentUpdateLanePriority = newLanePriority; +export function setCurrentUpdateLanePriority(newUpdateLane: Lane) { + currentUpdateLane = newUpdateLane; } -// "Registers" used to "return" multiple values -// Used by getHighestPriorityLanes and getNextLanes: -let return_highestLanePriority: LanePriority = DefaultLanePriority; - function getHighestPriorityLanes(lanes: Lanes | Lane): Lanes { - switch (getHighestPriorityLane(lanes)) { + const highestPriorityLane = getHighestPriorityLane(lanes); + // TODO: + if (highestPriorityLane & TransitionLanes) { + return lanes & TransitionLanes; + } + if (highestPriorityLane & RetryLanes) { + return lanes & RetryLanes; + } + return highestPriorityLane; +} + +export function laneToSchedulerPriority(lane: Lane): ReactPriorityLevel { + switch (lane) { case SyncLane: - return_highestLanePriority = SyncLanePriority; - return SyncLane; case SyncBatchedLane: - return_highestLanePriority = SyncBatchedLanePriority; - return SyncBatchedLane; - case InputDiscreteHydrationLane: - return_highestLanePriority = InputDiscreteHydrationLanePriority; - return InputDiscreteHydrationLane; - case InputDiscreteLane: - return_highestLanePriority = InputDiscreteLanePriority; - return InputDiscreteLane; + return ImmediateSchedulerPriority; case InputContinuousHydrationLane: - return_highestLanePriority = InputContinuousHydrationLanePriority; - return InputContinuousHydrationLane; case InputContinuousLane: - return_highestLanePriority = InputContinuousLanePriority; - return InputContinuousLane; + return UserBlockingSchedulerPriority; case DefaultHydrationLane: - return_highestLanePriority = DefaultHydrationLanePriority; - return DefaultHydrationLane; case DefaultLane: - return_highestLanePriority = DefaultLanePriority; - return DefaultLane; case TransitionHydrationLane: - return_highestLanePriority = TransitionHydrationPriority; - return TransitionHydrationLane; case TransitionLane1: case TransitionLane2: case TransitionLane3: @@ -242,68 +179,23 @@ function getHighestPriorityLanes(lanes: Lanes | Lane): Lanes { case TransitionLane12: case TransitionLane13: case TransitionLane14: - return_highestLanePriority = TransitionPriority; - return lanes & TransitionLanes; + case TransitionLane15: + case TransitionLane16: case RetryLane1: case RetryLane2: case RetryLane3: case RetryLane4: - return_highestLanePriority = RetryLanePriority; - return lanes & RetryLanes; case SelectiveHydrationLane: - return_highestLanePriority = SelectiveHydrationLanePriority; - return SelectiveHydrationLane; + return NormalSchedulerPriority; case IdleHydrationLane: - return_highestLanePriority = IdleHydrationLanePriority; - return IdleHydrationLane; case IdleLane: - return_highestLanePriority = IdleLanePriority; - return IdleLane; case OffscreenLane: - return_highestLanePriority = OffscreenLanePriority; - return OffscreenLane; - default: - if (__DEV__) { - console.error( - 'Should have found matching lanes. This is a bug in React.', - ); - } - // This shouldn't be reachable, but as a fallback, return the entire bitmask. - return_highestLanePriority = DefaultLanePriority; - return lanes; - } -} - -export function lanePriorityToSchedulerPriority( - lanePriority: LanePriority, -): ReactPriorityLevel { - switch (lanePriority) { - case SyncLanePriority: - case SyncBatchedLanePriority: - return ImmediateSchedulerPriority; - case InputDiscreteHydrationLanePriority: - case InputDiscreteLanePriority: - case InputContinuousHydrationLanePriority: - case InputContinuousLanePriority: - return UserBlockingSchedulerPriority; - case DefaultHydrationLanePriority: - case DefaultLanePriority: - case TransitionHydrationPriority: - case TransitionPriority: - case SelectiveHydrationLanePriority: - case RetryLanePriority: - return NormalSchedulerPriority; - case IdleHydrationLanePriority: - case IdleLanePriority: - case OffscreenLanePriority: return IdleSchedulerPriority; - case NoLanePriority: - return NoSchedulerPriority; default: invariant( false, 'Invalid update priority: %s. This is a bug in React.', - lanePriority, + lane, ); } } @@ -312,12 +204,10 @@ export function getNextLanes(root: FiberRoot, wipLanes: Lanes): Lanes { // Early bailout if there's no pending work left. const pendingLanes = root.pendingLanes; if (pendingLanes === NoLanes) { - return_highestLanePriority = NoLanePriority; return NoLanes; } let nextLanes = NoLanes; - let nextLanePriority = NoLanePriority; const expiredLanes = root.expiredLanes; const suspendedLanes = root.suspendedLanes; @@ -327,7 +217,6 @@ export function getNextLanes(root: FiberRoot, wipLanes: Lanes): Lanes { if (expiredLanes !== NoLanes) { // TODO: Should entangle with SyncLane nextLanes = expiredLanes; - nextLanePriority = return_highestLanePriority = SyncLanePriority; } else { // Do not work on any idle work until all the non-idle work has finished, // even if the work is suspended. @@ -336,12 +225,10 @@ export function getNextLanes(root: FiberRoot, wipLanes: Lanes): Lanes { const nonIdleUnblockedLanes = nonIdlePendingLanes & ~suspendedLanes; if (nonIdleUnblockedLanes !== NoLanes) { nextLanes = getHighestPriorityLanes(nonIdleUnblockedLanes); - nextLanePriority = return_highestLanePriority; } else { const nonIdlePingedLanes = nonIdlePendingLanes & pingedLanes; if (nonIdlePingedLanes !== NoLanes) { nextLanes = getHighestPriorityLanes(nonIdlePingedLanes); - nextLanePriority = return_highestLanePriority; } } } else { @@ -349,11 +236,9 @@ export function getNextLanes(root: FiberRoot, wipLanes: Lanes): Lanes { const unblockedLanes = pendingLanes & ~suspendedLanes; if (unblockedLanes !== NoLanes) { nextLanes = getHighestPriorityLanes(unblockedLanes); - nextLanePriority = return_highestLanePriority; } else { if (pingedLanes !== NoLanes) { nextLanes = getHighestPriorityLanes(pingedLanes); - nextLanePriority = return_highestLanePriority; } } } @@ -375,20 +260,21 @@ export function getNextLanes(root: FiberRoot, wipLanes: Lanes): Lanes { // bother waiting until the root is complete. (wipLanes & suspendedLanes) === NoLanes ) { - getHighestPriorityLanes(wipLanes); - const wipLanePriority = return_highestLanePriority; + const inProgressHighestPriorityLane = getHighestPriorityLane(wipLanes); + const nextHighestPriorityLane = getHighestPriorityLane(nextLanes); + // This works because the rightmost bits are highest priority. + const nextLaneIsHigherPriority = + nextHighestPriorityLane < inProgressHighestPriorityLane; if ( - nextLanePriority <= wipLanePriority || + !nextLaneIsHigherPriority || // Default priority updates should not interrupt transition updates. The // only difference between default updates and transition updates is that // default updates do not support refresh transitions. - (nextLanePriority === DefaultLanePriority && - wipLanePriority === TransitionPriority) + (nextHighestPriorityLane === DefaultLane && + (inProgressHighestPriorityLane & TransitionLanes) !== NoLanes) ) { // Keep working on the existing in-progress tree. Do not interrupt. return wipLanes; - } else { - return_highestLanePriority = nextLanePriority; } } @@ -451,31 +337,50 @@ export function getMostRecentEventTime(root: FiberRoot, lanes: Lanes): number { } function computeExpirationTime(lane: Lane, currentTime: number) { - // TODO: Expiration heuristic is constant per lane, so could use a map. - getHighestPriorityLanes(lane); - const priority = return_highestLanePriority; - if (priority >= InputContinuousLanePriority) { - // User interactions should expire slightly more quickly. - // - // NOTE: This is set to the corresponding constant as in Scheduler.js. When - // we made it larger, a product metric in www regressed, suggesting there's - // a user interaction that's being starved by a series of synchronous - // updates. If that theory is correct, the proper solution is to fix the - // starvation. However, this scenario supports the idea that expiration - // times are an important safeguard when starvation does happen. - // - // Also note that, in the case of user input specifically, this will soon no - // longer be an issue because we plan to make user input synchronous by - // default (until you enter `startTransition`, of course.) - // - // If weren't planning to make these updates synchronous soon anyway, I - // would probably make this number a configurable parameter. - return currentTime + 250; - } else if (priority >= TransitionPriority) { - return currentTime + 5000; - } else { - // Anything idle priority or lower should never expire. - return NoTimestamp; + switch (lane) { + case SyncLane: + case SyncBatchedLane: + case InputContinuousHydrationLane: + case InputContinuousLane: + // User interactions should expire slightly more quickly. + return currentTime + 250; + case DefaultHydrationLane: + case DefaultLane: + case TransitionHydrationLane: + case TransitionLane1: + case TransitionLane2: + case TransitionLane3: + case TransitionLane4: + case TransitionLane5: + case TransitionLane6: + case TransitionLane7: + case TransitionLane8: + case TransitionLane9: + case TransitionLane10: + case TransitionLane11: + case TransitionLane12: + case TransitionLane13: + case TransitionLane14: + case TransitionLane15: + case TransitionLane16: + case RetryLane1: + case RetryLane2: + case RetryLane3: + case RetryLane4: + return currentTime + 5000; + case SelectiveHydrationLane: + case IdleHydrationLane: + case IdleLane: + case OffscreenLane: + // Anything idle priority or lower should never expire. + return NoTimestamp; + default: + if (__DEV__) { + console.error( + 'Should have found matching lanes. This is a bug in React.', + ); + } + return NoTimestamp; } } @@ -538,9 +443,6 @@ export function getLanesToRetrySynchronouslyOnError(root: FiberRoot): Lanes { return NoLanes; } -export function returnNextLanesPriority() { - return return_highestLanePriority; -} export function includesNonIdleWork(lanes: Lanes) { return (lanes & NonIdleLanes) !== NoLanes; } @@ -555,39 +457,6 @@ export function isTransitionLane(lane: Lane) { return (lane & TransitionLanes) !== 0; } -// To ensure consistency across multiple updates in the same event, this should -// be a pure function, so that it always returns the same lane for given inputs. -export function findUpdateLane(lanePriority: LanePriority): Lane { - switch (lanePriority) { - case NoLanePriority: - break; - case SyncLanePriority: - return SyncLane; - case SyncBatchedLanePriority: - return SyncBatchedLane; - case InputDiscreteLanePriority: - return SyncLane; - case InputContinuousLanePriority: - return InputContinuousLane; - case DefaultLanePriority: - return DefaultLane; - case TransitionPriority: // Should be handled by findTransitionLane instead - case RetryLanePriority: // Should be handled by findRetryLane instead - break; - case IdleLanePriority: - return IdleLane; - default: - // The remaining priorities are not valid for updates - break; - } - - invariant( - false, - 'Invalid update priority: %s. This is a bug in React.', - lanePriority, - ); -} - export function claimNextTransitionLane(): Lane { // Cycle through the lanes, assigning each new transition to the next lane. // In most cases, this means every transition gets its own lane, until we @@ -660,13 +529,6 @@ export function higherPriorityLane(a: Lane, b: Lane) { return a !== NoLane && a < b ? a : b; } -export function higherLanePriority( - a: LanePriority, - b: LanePriority, -): LanePriority { - return a !== NoLanePriority && a > b ? a : b; -} - export function createLaneMap(initial: T): LaneMap { // Intentionally pushing one by one. // https://v8.dev/blog/elements-kinds#avoid-creating-holes @@ -817,49 +679,62 @@ export function getBumpedLaneForHydration( root: FiberRoot, renderLanes: Lanes, ): Lane { - getHighestPriorityLanes(renderLanes); - const highestLanePriority = return_highestLanePriority; + const renderLane = getHighestPriorityLane(renderLanes); let lane; - switch (highestLanePriority) { - case SyncLanePriority: - case SyncBatchedLanePriority: + switch (renderLane) { + case SyncLane: + case SyncBatchedLane: + // Sync updates don't have special hydration lanes. lane = NoLane; break; - case InputDiscreteHydrationLanePriority: - case InputDiscreteLanePriority: - lane = InputDiscreteHydrationLane; - break; - case InputContinuousHydrationLanePriority: - case InputContinuousLanePriority: + case InputContinuousHydrationLane: + case InputContinuousLane: lane = InputContinuousHydrationLane; break; - case DefaultHydrationLanePriority: - case DefaultLanePriority: + case DefaultHydrationLane: + case DefaultLane: lane = DefaultHydrationLane; break; - case TransitionHydrationPriority: - case TransitionPriority: + case TransitionHydrationLane: + case TransitionLane1: + case TransitionLane2: + case TransitionLane3: + case TransitionLane4: + case TransitionLane5: + case TransitionLane6: + case TransitionLane7: + case TransitionLane8: + case TransitionLane9: + case TransitionLane10: + case TransitionLane11: + case TransitionLane12: + case TransitionLane13: + case TransitionLane14: + case TransitionLane15: + case TransitionLane16: lane = TransitionHydrationLane; break; - case RetryLanePriority: + case RetryLane1: + case RetryLane2: + case RetryLane3: + case RetryLane4: // Shouldn't be reachable under normal circumstances, so there's no - // dedicated lane for retry priority. Use the one for long transitions. + // dedicated lane for retry priority. Use the one for transitions. lane = TransitionHydrationLane; break; - case SelectiveHydrationLanePriority: + case SelectiveHydrationLane: lane = SelectiveHydrationLane; break; - case IdleHydrationLanePriority: - case IdleLanePriority: + case IdleHydrationLane: lane = IdleHydrationLane; break; - case OffscreenLanePriority: - case NoLanePriority: - lane = NoLane; + case IdleLane: + lane = IdleLane; break; default: - invariant(false, 'Invalid lane: %s. This is a bug in React.', lane); + lane = NoLane; + break; } // Check if the lane we chose is suspended. If so, that indicates that we diff --git a/packages/shared/ReactFeatureFlags.js b/packages/shared/ReactFeatureFlags.js index 2a3d0a337bf88..591a24c3cd317 100644 --- a/packages/shared/ReactFeatureFlags.js +++ b/packages/shared/ReactFeatureFlags.js @@ -114,6 +114,7 @@ export const skipUnmountedBoundaries = false; // When a node is unmounted, recurse into the Fiber subtree and clean out references. export const enableStrongMemoryCleanup = false; +export const enableDetachOldChildList = false; // -------------------------- // Future APIs to be deprecated diff --git a/packages/shared/forks/ReactFeatureFlags.native-fb.js b/packages/shared/forks/ReactFeatureFlags.native-fb.js index 443c489c0063f..913063d587be3 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-fb.js +++ b/packages/shared/forks/ReactFeatureFlags.native-fb.js @@ -47,6 +47,7 @@ export const enableFilterEmptyStringAttributesDOM = false; export const disableNativeComponentFrames = false; export const skipUnmountedBoundaries = false; export const enableStrongMemoryCleanup = false; +export const enableDetachOldChildList = false; 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 bac13f5091b78..8714352a17686 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-oss.js +++ b/packages/shared/forks/ReactFeatureFlags.native-oss.js @@ -46,6 +46,7 @@ export const enableFilterEmptyStringAttributesDOM = false; export const disableNativeComponentFrames = false; export const skipUnmountedBoundaries = false; export const enableStrongMemoryCleanup = false; +export const enableDetachOldChildList = false; 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 da03038c0211a..0ea1b5fda395a 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.js @@ -46,6 +46,7 @@ export const enableFilterEmptyStringAttributesDOM = false; export const disableNativeComponentFrames = false; export const skipUnmountedBoundaries = false; export const enableStrongMemoryCleanup = false; +export const enableDetachOldChildList = false; export const enableNewReconciler = false; export const deferRenderPhaseUpdateToNextBatch = true; diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.native.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.native.js index eda47cde1139b..db62ddc1dc10e 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.native.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.native.js @@ -46,6 +46,7 @@ export const enableFilterEmptyStringAttributesDOM = false; export const disableNativeComponentFrames = false; export const skipUnmountedBoundaries = false; export const enableStrongMemoryCleanup = false; +export const enableDetachOldChildList = false; 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 9b02f6408229f..46fd65d187658 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js @@ -46,6 +46,7 @@ export const enableFilterEmptyStringAttributesDOM = false; export const disableNativeComponentFrames = false; export const skipUnmountedBoundaries = false; export const enableStrongMemoryCleanup = false; +export const enableDetachOldChildList = false; 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 7bb7ed424c7bd..144ce7f4dca87 100644 --- a/packages/shared/forks/ReactFeatureFlags.testing.js +++ b/packages/shared/forks/ReactFeatureFlags.testing.js @@ -46,6 +46,7 @@ export const enableFilterEmptyStringAttributesDOM = false; export const disableNativeComponentFrames = false; export const skipUnmountedBoundaries = false; export const enableStrongMemoryCleanup = false; +export const enableDetachOldChildList = false; 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 8834238b02b14..188c6bdcffdfe 100644 --- a/packages/shared/forks/ReactFeatureFlags.testing.www.js +++ b/packages/shared/forks/ReactFeatureFlags.testing.www.js @@ -46,6 +46,7 @@ export const enableFilterEmptyStringAttributesDOM = false; export const disableNativeComponentFrames = false; export const skipUnmountedBoundaries = true; export const enableStrongMemoryCleanup = false; +export const enableDetachOldChildList = false; export const enableNewReconciler = false; export const deferRenderPhaseUpdateToNextBatch = true; diff --git a/packages/shared/forks/ReactFeatureFlags.www-dynamic.js b/packages/shared/forks/ReactFeatureFlags.www-dynamic.js index f58e0da1e80b9..bd666333c5f72 100644 --- a/packages/shared/forks/ReactFeatureFlags.www-dynamic.js +++ b/packages/shared/forks/ReactFeatureFlags.www-dynamic.js @@ -53,6 +53,7 @@ export const createRootStrictEffectsByDefault = false; export const enableStrictEffects = false; export const enableUseRefAccessWarning = __VARIANT__; export const enableStrongMemoryCleanup = __VARIANT__; +export const enableDetachOldChildList = __VARIANT__; export const enableProfilerNestedUpdateScheduledHook = __VARIANT__; export const disableSchedulerTimeoutInWorkLoop = __VARIANT__; diff --git a/packages/shared/forks/ReactFeatureFlags.www.js b/packages/shared/forks/ReactFeatureFlags.www.js index 25b88a019f1da..0f9e27011af06 100644 --- a/packages/shared/forks/ReactFeatureFlags.www.js +++ b/packages/shared/forks/ReactFeatureFlags.www.js @@ -34,6 +34,7 @@ export const { enableSyncMicroTasks, enableLazyContextPropagation, enableStrongMemoryCleanup, + enableDetachOldChildList, } = dynamicFeatureFlags; // On WWW, __EXPERIMENTAL__ is used for a new modern build.