From c9602e94f78e54f5aaaca5ff3060cd94b01f4ad4 Mon Sep 17 00:00:00 2001 From: Sebastian Sebbie Silbermann Date: Wed, 10 Sep 2025 21:56:36 +0200 Subject: [PATCH 1/2] [DevTools] Stop recording reorders in disconnected subtrees --- .../src/backend/fiber/renderer.js | 65 +++++++++++++++---- 1 file changed, 51 insertions(+), 14 deletions(-) diff --git a/packages/react-devtools-shared/src/backend/fiber/renderer.js b/packages/react-devtools-shared/src/backend/fiber/renderer.js index 12e2ce31fb16f..ce2cb4c4d8152 100644 --- a/packages/react-devtools-shared/src/backend/fiber/renderer.js +++ b/packages/react-devtools-shared/src/backend/fiber/renderer.js @@ -4405,8 +4405,10 @@ export function attach( traceNearestHostComponentUpdate, virtualLevel, ); - updateFlags |= - ShouldResetChildren | ShouldResetSuspenseChildren; + updateFlags |= ShouldResetSuspenseChildren; + if (!isInDisconnectedSubtree) { + updateFlags |= ShouldResetChildren; + } } else { updateFlags |= updateVirtualInstanceRecursively( previousVirtualInstance, @@ -4459,7 +4461,10 @@ export function attach( insertChild(newVirtualInstance); previousVirtualInstance = newVirtualInstance; previousVirtualInstanceWasMount = true; - updateFlags |= ShouldResetChildren; + updateFlags |= ShouldResetSuspenseChildren; + if (!isInDisconnectedSubtree) { + updateFlags |= ShouldResetChildren; + } } // Existing children might be reparented into this new virtual instance. // TODO: This will cause the front end to error which needs to be fixed. @@ -4486,7 +4491,10 @@ export function attach( traceNearestHostComponentUpdate, virtualLevel, ); - updateFlags |= ShouldResetChildren | ShouldResetSuspenseChildren; + updateFlags |= ShouldResetSuspenseChildren; + if (!isInDisconnectedSubtree) { + updateFlags |= ShouldResetChildren; + } } else { updateFlags |= updateVirtualInstanceRecursively( previousVirtualInstance, @@ -4538,7 +4546,10 @@ export function attach( // They are always different referentially, but if the instances line up // conceptually we'll want to know that. if (prevChild !== prevChildAtSameIndex) { - updateFlags |= ShouldResetChildren | ShouldResetSuspenseChildren; + updateFlags |= ShouldResetSuspenseChildren; + if (!isInDisconnectedSubtree) { + updateFlags |= ShouldResetChildren; + } } moveChild(fiberInstance, previousSiblingOfExistingInstance); @@ -4555,7 +4566,10 @@ export function attach( } else if (prevChild !== null && shouldFilterFiber(nextChild)) { // The filtered instance could've reordered. if (prevChild !== prevChildAtSameIndex) { - updateFlags |= ShouldResetChildren | ShouldResetSuspenseChildren; + updateFlags |= ShouldResetSuspenseChildren; + if (!isInDisconnectedSubtree) { + updateFlags |= ShouldResetChildren; + } } // If this Fiber should be filtered, we need to still update its children. @@ -4579,7 +4593,10 @@ export function attach( mountFiberRecursively(nextChild, traceNearestHostComponentUpdate); // Need to mark the parent set to remount the new instance. - updateFlags |= ShouldResetChildren | ShouldResetSuspenseChildren; + updateFlags |= ShouldResetSuspenseChildren; + if (!isInDisconnectedSubtree) { + updateFlags |= ShouldResetChildren; + } } } // Try the next child. @@ -4602,7 +4619,10 @@ export function attach( traceNearestHostComponentUpdate, virtualLevel, ); - updateFlags |= ShouldResetChildren | ShouldResetSuspenseChildren; + updateFlags |= ShouldResetSuspenseChildren; + if (!isInDisconnectedSubtree) { + updateFlags |= ShouldResetChildren; + } } else { updateFlags |= updateVirtualInstanceRecursively( previousVirtualInstance, @@ -4616,7 +4636,10 @@ export function attach( } // If we have no more children, but used to, they don't line up. if (prevChildAtSameIndex !== null) { - updateFlags |= ShouldResetChildren | ShouldResetSuspenseChildren; + updateFlags |= ShouldResetSuspenseChildren; + if (!isInDisconnectedSubtree) { + updateFlags |= ShouldResetChildren; + } } return updateFlags; } @@ -4628,7 +4651,9 @@ export function attach( traceNearestHostComponentUpdate: boolean, ): UpdateFlags { if (nextFirstChild === null) { - return prevFirstChild !== null ? ShouldResetChildren : NoUpdate; + return prevFirstChild !== null && !isInDisconnectedSubtree + ? ShouldResetChildren + : NoUpdate; } return updateVirtualChildrenRecursively( nextFirstChild, @@ -4854,7 +4879,10 @@ export function attach( traceNearestHostComponentUpdate, ); - updateFlags |= ShouldResetChildren | ShouldResetSuspenseChildren; + updateFlags |= ShouldResetSuspenseChildren; + if (!isInDisconnectedSubtree) { + updateFlags |= ShouldResetChildren; + } } const childrenUpdateFlags = @@ -4877,7 +4905,10 @@ export function attach( nextPrimaryChildSet, traceNearestHostComponentUpdate, ); - updateFlags |= ShouldResetChildren | ShouldResetSuspenseChildren; + updateFlags |= ShouldResetSuspenseChildren; + if (!isInDisconnectedSubtree) { + updateFlags |= ShouldResetChildren; + } } } else if (!prevDidTimeout && nextDidTimeOut) { // Primary -> Fallback: @@ -4894,7 +4925,10 @@ export function attach( nextFallbackChildSet, traceNearestHostComponentUpdate, ); - updateFlags |= ShouldResetChildren | ShouldResetSuspenseChildren; + updateFlags |= ShouldResetSuspenseChildren; + if (!isInDisconnectedSubtree) { + updateFlags |= ShouldResetChildren; + } } } else if (nextIsHidden) { if (!prevWasHidden) { @@ -4939,7 +4973,10 @@ export function attach( if (fiberInstance !== null && !isInDisconnectedSubtree) { reconnectChildrenRecursively(fiberInstance); // Children may have reordered while they were hidden. - updateFlags |= ShouldResetChildren | ShouldResetSuspenseChildren; + updateFlags |= ShouldResetSuspenseChildren; + if (!isInDisconnectedSubtree) { + updateFlags |= ShouldResetChildren; + } } } else if ( nextFiber.tag === SuspenseComponent && From 7836f1fa8fe8ab8c17e3f6cd68bb64d6a4530d0e Mon Sep 17 00:00:00 2001 From: Sebastian Sebbie Silbermann Date: Thu, 11 Sep 2025 18:32:38 +0200 Subject: [PATCH 2/2] Check callsite instead --- .../src/backend/fiber/renderer.js | 73 +++++-------------- 1 file changed, 20 insertions(+), 53 deletions(-) diff --git a/packages/react-devtools-shared/src/backend/fiber/renderer.js b/packages/react-devtools-shared/src/backend/fiber/renderer.js index ce2cb4c4d8152..3fe177e0797f1 100644 --- a/packages/react-devtools-shared/src/backend/fiber/renderer.js +++ b/packages/react-devtools-shared/src/backend/fiber/renderer.js @@ -4310,7 +4310,9 @@ export function attach( virtualLevel + 1, ); if ((updateFlags & ShouldResetChildren) !== NoUpdate) { - recordResetChildren(virtualInstance); + if (!isInDisconnectedSubtree) { + recordResetChildren(virtualInstance); + } updateFlags &= ~ShouldResetChildren; } removePreviousSuspendedBy( @@ -4405,10 +4407,8 @@ export function attach( traceNearestHostComponentUpdate, virtualLevel, ); - updateFlags |= ShouldResetSuspenseChildren; - if (!isInDisconnectedSubtree) { - updateFlags |= ShouldResetChildren; - } + updateFlags |= + ShouldResetChildren | ShouldResetSuspenseChildren; } else { updateFlags |= updateVirtualInstanceRecursively( previousVirtualInstance, @@ -4461,10 +4461,7 @@ export function attach( insertChild(newVirtualInstance); previousVirtualInstance = newVirtualInstance; previousVirtualInstanceWasMount = true; - updateFlags |= ShouldResetSuspenseChildren; - if (!isInDisconnectedSubtree) { - updateFlags |= ShouldResetChildren; - } + updateFlags |= ShouldResetChildren; } // Existing children might be reparented into this new virtual instance. // TODO: This will cause the front end to error which needs to be fixed. @@ -4491,10 +4488,7 @@ export function attach( traceNearestHostComponentUpdate, virtualLevel, ); - updateFlags |= ShouldResetSuspenseChildren; - if (!isInDisconnectedSubtree) { - updateFlags |= ShouldResetChildren; - } + updateFlags |= ShouldResetChildren | ShouldResetSuspenseChildren; } else { updateFlags |= updateVirtualInstanceRecursively( previousVirtualInstance, @@ -4546,10 +4540,7 @@ export function attach( // They are always different referentially, but if the instances line up // conceptually we'll want to know that. if (prevChild !== prevChildAtSameIndex) { - updateFlags |= ShouldResetSuspenseChildren; - if (!isInDisconnectedSubtree) { - updateFlags |= ShouldResetChildren; - } + updateFlags |= ShouldResetChildren | ShouldResetSuspenseChildren; } moveChild(fiberInstance, previousSiblingOfExistingInstance); @@ -4566,10 +4557,7 @@ export function attach( } else if (prevChild !== null && shouldFilterFiber(nextChild)) { // The filtered instance could've reordered. if (prevChild !== prevChildAtSameIndex) { - updateFlags |= ShouldResetSuspenseChildren; - if (!isInDisconnectedSubtree) { - updateFlags |= ShouldResetChildren; - } + updateFlags |= ShouldResetChildren | ShouldResetSuspenseChildren; } // If this Fiber should be filtered, we need to still update its children. @@ -4593,10 +4581,7 @@ export function attach( mountFiberRecursively(nextChild, traceNearestHostComponentUpdate); // Need to mark the parent set to remount the new instance. - updateFlags |= ShouldResetSuspenseChildren; - if (!isInDisconnectedSubtree) { - updateFlags |= ShouldResetChildren; - } + updateFlags |= ShouldResetChildren | ShouldResetSuspenseChildren; } } // Try the next child. @@ -4619,10 +4604,7 @@ export function attach( traceNearestHostComponentUpdate, virtualLevel, ); - updateFlags |= ShouldResetSuspenseChildren; - if (!isInDisconnectedSubtree) { - updateFlags |= ShouldResetChildren; - } + updateFlags |= ShouldResetChildren | ShouldResetSuspenseChildren; } else { updateFlags |= updateVirtualInstanceRecursively( previousVirtualInstance, @@ -4636,10 +4618,7 @@ export function attach( } // If we have no more children, but used to, they don't line up. if (prevChildAtSameIndex !== null) { - updateFlags |= ShouldResetSuspenseChildren; - if (!isInDisconnectedSubtree) { - updateFlags |= ShouldResetChildren; - } + updateFlags |= ShouldResetChildren | ShouldResetSuspenseChildren; } return updateFlags; } @@ -4651,9 +4630,7 @@ export function attach( traceNearestHostComponentUpdate: boolean, ): UpdateFlags { if (nextFirstChild === null) { - return prevFirstChild !== null && !isInDisconnectedSubtree - ? ShouldResetChildren - : NoUpdate; + return prevFirstChild !== null ? ShouldResetChildren : NoUpdate; } return updateVirtualChildrenRecursively( nextFirstChild, @@ -4879,10 +4856,7 @@ export function attach( traceNearestHostComponentUpdate, ); - updateFlags |= ShouldResetSuspenseChildren; - if (!isInDisconnectedSubtree) { - updateFlags |= ShouldResetChildren; - } + updateFlags |= ShouldResetChildren | ShouldResetSuspenseChildren; } const childrenUpdateFlags = @@ -4905,10 +4879,7 @@ export function attach( nextPrimaryChildSet, traceNearestHostComponentUpdate, ); - updateFlags |= ShouldResetSuspenseChildren; - if (!isInDisconnectedSubtree) { - updateFlags |= ShouldResetChildren; - } + updateFlags |= ShouldResetChildren | ShouldResetSuspenseChildren; } } else if (!prevDidTimeout && nextDidTimeOut) { // Primary -> Fallback: @@ -4925,10 +4896,7 @@ export function attach( nextFallbackChildSet, traceNearestHostComponentUpdate, ); - updateFlags |= ShouldResetSuspenseChildren; - if (!isInDisconnectedSubtree) { - updateFlags |= ShouldResetChildren; - } + updateFlags |= ShouldResetChildren | ShouldResetSuspenseChildren; } } else if (nextIsHidden) { if (!prevWasHidden) { @@ -4973,10 +4941,7 @@ export function attach( if (fiberInstance !== null && !isInDisconnectedSubtree) { reconnectChildrenRecursively(fiberInstance); // Children may have reordered while they were hidden. - updateFlags |= ShouldResetSuspenseChildren; - if (!isInDisconnectedSubtree) { - updateFlags |= ShouldResetChildren; - } + updateFlags |= ShouldResetChildren | ShouldResetSuspenseChildren; } } else if ( nextFiber.tag === SuspenseComponent && @@ -5134,7 +5099,9 @@ export function attach( // We need to crawl the subtree for closest non-filtered Fibers // so that we can display them in a flat children set. if (fiberInstance !== null && fiberInstance.kind === FIBER_INSTANCE) { - recordResetChildren(fiberInstance); + if (!nextIsHidden && !isInDisconnectedSubtree) { + recordResetChildren(fiberInstance); + } // We've handled the child order change for this Fiber. // Since it's included, there's no need to invalidate parent child order.