Skip to content

Commit ba4bdb2

Browse files
authored
[DevTools] Consume SuspenseNodes that were skipped when we're bailing out of a subtree (facebook#34082)
This searches through the remaining children to see if any of them were children of the bailed out FiberInstance and if so we should reuse them in the new set. It's faster to do this than search through children of the FiberInstance for Suspense boundaries.
1 parent be11cb5 commit ba4bdb2

File tree

1 file changed

+87
-9
lines changed
  • packages/react-devtools-shared/src/backend/fiber

1 file changed

+87
-9
lines changed

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

Lines changed: 87 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2701,6 +2701,76 @@ export function attach(
27012701
}
27022702
}
27032703
2704+
function isChildOf(
2705+
parentInstance: DevToolsInstance,
2706+
childInstance: DevToolsInstance,
2707+
grandParent: DevToolsInstance,
2708+
): boolean {
2709+
let instance = childInstance.parent;
2710+
while (instance !== null) {
2711+
if (parentInstance === instance) {
2712+
return true;
2713+
}
2714+
if (instance === parentInstance.parent || instance === grandParent) {
2715+
// This was a sibling but not inside the FiberInstance. We can bail out.
2716+
break;
2717+
}
2718+
instance = instance.parent;
2719+
}
2720+
return false;
2721+
}
2722+
2723+
function consumeSuspenseNodesOfExistingInstance(
2724+
instance: DevToolsInstance,
2725+
): void {
2726+
// We need to also consume any unchanged Suspense boundaries.
2727+
let suspenseNode = remainingReconcilingChildrenSuspenseNodes;
2728+
if (suspenseNode === null) {
2729+
return;
2730+
}
2731+
const parentSuspenseNode = reconcilingParentSuspenseNode;
2732+
if (parentSuspenseNode === null) {
2733+
throw new Error(
2734+
'The should not be any remaining suspense node children if there is no parent.',
2735+
);
2736+
}
2737+
let foundOne = false;
2738+
let previousSkippedSibling = null;
2739+
while (suspenseNode !== null) {
2740+
// Check if this SuspenseNode was a child of the bailed out FiberInstance.
2741+
if (
2742+
isChildOf(instance, suspenseNode.instance, parentSuspenseNode.instance)
2743+
) {
2744+
foundOne = true;
2745+
// The suspenseNode was child of the bailed out Fiber.
2746+
// First, remove it from the remaining children set.
2747+
const nextRemainingSibling = suspenseNode.nextSibling;
2748+
if (previousSkippedSibling === null) {
2749+
remainingReconcilingChildrenSuspenseNodes = nextRemainingSibling;
2750+
} else {
2751+
previousSkippedSibling.nextSibling = nextRemainingSibling;
2752+
}
2753+
suspenseNode.nextSibling = null;
2754+
// Then, re-insert it into the newly reconciled set.
2755+
if (previouslyReconciledSiblingSuspenseNode === null) {
2756+
parentSuspenseNode.firstChild = suspenseNode;
2757+
} else {
2758+
previouslyReconciledSiblingSuspenseNode.nextSibling = suspenseNode;
2759+
}
2760+
previouslyReconciledSiblingSuspenseNode = suspenseNode;
2761+
// Continue
2762+
suspenseNode = nextRemainingSibling;
2763+
} else if (foundOne) {
2764+
// If we found one and then hit a miss, we assume that we're passed the sequence because
2765+
// they should've all been consecutive.
2766+
break;
2767+
} else {
2768+
previousSkippedSibling = suspenseNode;
2769+
suspenseNode = suspenseNode.nextSibling;
2770+
}
2771+
}
2772+
}
2773+
27042774
function mountVirtualInstanceRecursively(
27052775
virtualInstance: VirtualInstance,
27062776
firstChild: Fiber,
@@ -3094,9 +3164,11 @@ export function attach(
30943164
reconcilingParent = stashedParent;
30953165
previouslyReconciledSibling = stashedPrevious;
30963166
remainingReconcilingChildren = stashedRemaining;
3097-
reconcilingParentSuspenseNode = stashedSuspenseParent;
3098-
previouslyReconciledSiblingSuspenseNode = stashedSuspensePrevious;
3099-
remainingReconcilingChildrenSuspenseNodes = stashedSuspenseRemaining;
3167+
if (instance.suspenseNode !== null) {
3168+
reconcilingParentSuspenseNode = stashedSuspenseParent;
3169+
previouslyReconciledSiblingSuspenseNode = stashedSuspensePrevious;
3170+
remainingReconcilingChildrenSuspenseNodes = stashedSuspenseRemaining;
3171+
}
31003172
}
31013173
if (instance.kind === FIBER_INSTANCE) {
31023174
recordUnmount(instance);
@@ -3688,10 +3760,12 @@ export function attach(
36883760
fiberInstance.firstChild = null;
36893761
fiberInstance.suspendedBy = null;
36903762
3691-
if (fiberInstance.suspenseNode !== null) {
3692-
reconcilingParentSuspenseNode = fiberInstance.suspenseNode;
3763+
const suspenseNode = fiberInstance.suspenseNode;
3764+
if (suspenseNode !== null) {
3765+
reconcilingParentSuspenseNode = suspenseNode;
36933766
previouslyReconciledSiblingSuspenseNode = null;
3694-
remainingReconcilingChildrenSuspenseNodes = null;
3767+
remainingReconcilingChildrenSuspenseNodes = suspenseNode.firstChild;
3768+
suspenseNode.firstChild = null;
36953769
}
36963770
}
36973771
try {
@@ -3849,6 +3923,8 @@ export function attach(
38493923
fiberInstance.firstChild = remainingReconcilingChildren;
38503924
remainingReconcilingChildren = null;
38513925
3926+
consumeSuspenseNodesOfExistingInstance(fiberInstance);
3927+
38523928
if (traceUpdatesEnabled) {
38533929
// If we're tracing updates and we've bailed out before reaching a host node,
38543930
// we should fall back to recursively marking the nearest host descendants for highlight.
@@ -3919,9 +3995,11 @@ export function attach(
39193995
reconcilingParent = stashedParent;
39203996
previouslyReconciledSibling = stashedPrevious;
39213997
remainingReconcilingChildren = stashedRemaining;
3922-
reconcilingParentSuspenseNode = stashedSuspenseParent;
3923-
previouslyReconciledSiblingSuspenseNode = stashedSuspensePrevious;
3924-
remainingReconcilingChildrenSuspenseNodes = stashedSuspenseRemaining;
3998+
if (fiberInstance.suspenseNode !== null) {
3999+
reconcilingParentSuspenseNode = stashedSuspenseParent;
4000+
previouslyReconciledSiblingSuspenseNode = stashedSuspensePrevious;
4001+
remainingReconcilingChildrenSuspenseNodes = stashedSuspenseRemaining;
4002+
}
39254003
}
39264004
}
39274005
}

0 commit comments

Comments
 (0)