Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Unmount instance by walking the instance tree instead of the fiber tree
  • Loading branch information
sebmarkbage committed Aug 12, 2024
commit f6d24e1601111f7531a74129a5655a1c73fab0d0
101 changes: 32 additions & 69 deletions packages/react-devtools-shared/src/backend/fiber/renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -1148,8 +1148,9 @@ export function attach(

// Recursively unmount all roots.
hook.getFiberRoots(rendererID).forEach(root => {
currentRootID = getFiberInstanceThrows(root.current).id;
unmountFiberRecursively(root.current);
const rootInstance = getFiberInstanceThrows(root.current);
currentRootID = rootInstance.id;
unmountInstanceRecursively(rootInstance);
flushPendingEvents(root);
currentRootID = -1;
});
Expand Down Expand Up @@ -2308,10 +2309,7 @@ export function attach(
function unmountRemainingChildren() {
let child = remainingReconcilingChildren;
while (child !== null) {
if (child.kind === FIBER_INSTANCE) {
unmountFiberRecursively(child.data);
}
removeChild(child);
unmountInstanceRecursively(child);
child = remainingReconcilingChildren;
}
}
Expand Down Expand Up @@ -2434,69 +2432,33 @@ export function attach(

// We use this to simulate unmounting for Suspense trees
// when we switch from primary to fallback, or deleting a subtree.
function unmountFiberRecursively(fiber: Fiber) {
function unmountInstanceRecursively(instance: DevToolsInstance) {
if (__DEBUG__) {
debug('unmountFiberRecursively()', fiber, null);
if (instance.kind === FIBER_INSTANCE) {
debug('unmountInstanceRecursively()', instance.data, null);
}
}

let fiberInstance = null;

const shouldIncludeInTree = !shouldFilterFiber(fiber);
const stashedParent = reconcilingParent;
const stashedPrevious = previouslyReconciledSibling;
const stashedRemaining = remainingReconcilingChildren;
if (shouldIncludeInTree) {
fiberInstance = getFiberInstanceThrows(fiber);
// Push a new DevTools instance parent while reconciling this subtree.
reconcilingParent = fiberInstance;
previouslyReconciledSibling = null;
// Move all the children of this instance to the remaining set.
// We'll move them back one by one, and anything that remains is deleted.
remainingReconcilingChildren = fiberInstance.firstChild;
fiberInstance.firstChild = null;
}
// Push a new DevTools instance parent while reconciling this subtree.
reconcilingParent = instance;
previouslyReconciledSibling = null;
// Move all the children of this instance to the remaining set.
remainingReconcilingChildren = instance.firstChild;
try {
// We might meet a nested Suspense on our way.
const isTimedOutSuspense =
fiber.tag === SuspenseComponent && fiber.memoizedState !== null;

if (fiber.tag === HostHoistable) {
releaseHostResource(fiber, fiber.memoizedState);
}

let child = fiber.child;
if (isTimedOutSuspense) {
// If it's showing fallback tree, let's traverse it instead.
const primaryChildFragment = fiber.child;
const fallbackChildFragment = primaryChildFragment
? primaryChildFragment.sibling
: null;
// Skip over to the real Fiber child.
child = fallbackChildFragment ? fallbackChildFragment.child : null;
}

unmountChildrenRecursively(child);
// Unmount the remaining set.
unmountRemainingChildren();
} finally {
if (shouldIncludeInTree) {
reconcilingParent = stashedParent;
previouslyReconciledSibling = stashedPrevious;
remainingReconcilingChildren = stashedRemaining;
}
}
if (fiberInstance !== null) {
recordUnmount(fiber);
removeChild(fiberInstance);
reconcilingParent = stashedParent;
previouslyReconciledSibling = stashedPrevious;
remainingReconcilingChildren = stashedRemaining;
}
}

function unmountChildrenRecursively(firstChild: null | Fiber) {
let child: null | Fiber = firstChild;
while (child !== null) {
// Record simulated unmounts children-first.
// We skip nodes without return because those are real unmounts.
unmountFiberRecursively(child);
child = child.sibling;
if (instance.kind === FIBER_INSTANCE) {
recordUnmount(instance.data);
}
removeChild(instance);
}

function recordProfilingDurations(fiber: Fiber) {
Expand Down Expand Up @@ -2843,7 +2805,8 @@ export function attach(
} else if (!prevDidTimeout && nextDidTimeOut) {
// Primary -> Fallback:
// 1. Hide primary set
unmountChildrenRecursively(prevFiber.child);
// We simply don't re-add the fallback children and let
// unmountRemainingChildren() handle it.
// 2. Mount fallback set
const nextFiberChild = nextFiber.child;
const nextFallbackChildSet = nextFiberChild
Expand Down Expand Up @@ -3053,19 +3016,19 @@ export function attach(
const current = root.current;
const alternate = current.alternate;

const existingRoot =
let rootInstance =
fiberToFiberInstanceMap.get(current) ||
(alternate && fiberToFiberInstanceMap.get(alternate));
if (!existingRoot) {
const newRoot = createFiberInstance(current);
idToDevToolsInstanceMap.set(newRoot.id, newRoot);
fiberToFiberInstanceMap.set(current, newRoot);
if (!rootInstance) {
rootInstance = createFiberInstance(current);
idToDevToolsInstanceMap.set(rootInstance.id, rootInstance);
fiberToFiberInstanceMap.set(current, rootInstance);
if (alternate) {
fiberToFiberInstanceMap.set(alternate, newRoot);
fiberToFiberInstanceMap.set(alternate, rootInstance);
}
currentRootID = newRoot.id;
currentRootID = rootInstance.id;
} else {
currentRootID = existingRoot.id;
currentRootID = rootInstance.id;
}

// Before the traversals, remember to start tracking
Expand Down Expand Up @@ -3123,7 +3086,7 @@ export function attach(
} else if (wasMounted && !isMounted) {
// Unmount an existing root.
removeRootPseudoKey(currentRootID);
unmountFiberRecursively(alternate);
unmountInstanceRecursively(rootInstance);
}
} else {
// Mount a new root.
Expand Down