Skip to content

Commit 11604af

Browse files
committed
Consume SuspenseNodes that were skipped when we're bailing out of a subtree
1 parent 5abd5c9 commit 11604af

File tree

1 file changed

+72
-0
lines changed
  • packages/react-devtools-shared/src/backend/fiber

1 file changed

+72
-0
lines changed

packages/react-devtools-shared/src/backend/fiber/renderer.js

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2700,6 +2700,76 @@ export function attach(
27002700
}
27012701
}
27022702
2703+
function isChildOf(
2704+
parentInstance: DevToolsInstance,
2705+
childInstance: DevToolsInstance,
2706+
grandParent: DevToolsInstance,
2707+
): boolean {
2708+
let instance = childInstance.parent;
2709+
while (instance !== null) {
2710+
if (parentInstance === instance) {
2711+
return true;
2712+
}
2713+
if (instance === parentInstance.parent || instance === grandParent) {
2714+
// This was a sibling but not inside the FiberInstance. We can bail out.
2715+
break;
2716+
}
2717+
instance = instance.parent;
2718+
}
2719+
return false;
2720+
}
2721+
2722+
function consumeSuspenseNodesOfExistingInstance(
2723+
instance: DevToolsInstance,
2724+
): void {
2725+
// We need to also consume any unchanged Suspense boundaries.
2726+
let suspenseNode = remainingReconcilingChildrenSuspenseNodes;
2727+
if (suspenseNode === null) {
2728+
return;
2729+
}
2730+
const parentSuspenseNode = reconcilingParentSuspenseNode;
2731+
if (parentSuspenseNode === null) {
2732+
throw new Error(
2733+
'The should not be any remaining suspense node children if there is no parent.',
2734+
);
2735+
}
2736+
let foundOne = false;
2737+
let previousSkippedSibling = null;
2738+
while (suspenseNode !== null) {
2739+
// Check if this SuspenseNode was a child of the bailed out FiberInstance.
2740+
if (
2741+
isChildOf(instance, suspenseNode.instance, parentSuspenseNode.instance)
2742+
) {
2743+
foundOne = true;
2744+
// The suspenseNode was child of the bailed out Fiber.
2745+
// First, remove it from the remaining children set.
2746+
const nextRemainingSibling = suspenseNode.nextSibling;
2747+
if (previousSkippedSibling === null) {
2748+
remainingReconcilingChildrenSuspenseNodes = nextRemainingSibling;
2749+
} else {
2750+
previousSkippedSibling.nextSibling = nextRemainingSibling;
2751+
}
2752+
suspenseNode.nextSibling = null;
2753+
// Then, re-insert it into the newly reconciled set.
2754+
if (previouslyReconciledSiblingSuspenseNode === null) {
2755+
parentSuspenseNode.firstChild = suspenseNode;
2756+
} else {
2757+
previouslyReconciledSiblingSuspenseNode.nextSibling = suspenseNode;
2758+
}
2759+
previouslyReconciledSiblingSuspenseNode = suspenseNode;
2760+
// Continue
2761+
suspenseNode = nextRemainingSibling;
2762+
} else if (foundOne) {
2763+
// If we found one and then hit a miss, we assume that we're passed the sequence because
2764+
// they should've all been consecutive.
2765+
break;
2766+
} else {
2767+
previousSkippedSibling = suspenseNode;
2768+
suspenseNode = suspenseNode.nextSibling;
2769+
}
2770+
}
2771+
}
2772+
27032773
function mountVirtualInstanceRecursively(
27042774
virtualInstance: VirtualInstance,
27052775
firstChild: Fiber,
@@ -3848,6 +3918,8 @@ export function attach(
38483918
fiberInstance.firstChild = remainingReconcilingChildren;
38493919
remainingReconcilingChildren = null;
38503920
3921+
consumeSuspenseNodesOfExistingInstance(fiberInstance);
3922+
38513923
if (traceUpdatesEnabled) {
38523924
// If we're tracing updates and we've bailed out before reaching a host node,
38533925
// we should fall back to recursively marking the nearest host descendants for highlight.

0 commit comments

Comments
 (0)