Skip to content

Commit 1c7110e

Browse files
committed
Collapse parent nodes unless they're close to the edge
This collapses parent nodes of larger trees unless they're a fork, has diff information or is close to a leaf of the tree that has diff info.
1 parent df5325a commit 1c7110e

File tree

2 files changed

+47
-13
lines changed

2 files changed

+47
-13
lines changed

packages/react-reconciler/src/ReactFiberHydrationContext.js

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,10 @@ let hydrationErrors: Array<CapturedValue<mixed>> | null = null;
8282
let rootOrSingletonContext = false;
8383

8484
// Builds a common ancestor tree from the root down for collecting diffs.
85-
function buildHydrationDiffNode(fiber: Fiber): HydrationDiffNode {
85+
function buildHydrationDiffNode(
86+
fiber: Fiber,
87+
distanceFromLeaf: number,
88+
): HydrationDiffNode {
8689
if (fiber.return === null) {
8790
// We're at the root.
8891
if (hydrationDiffRootDEV === null) {
@@ -91,27 +94,38 @@ function buildHydrationDiffNode(fiber: Fiber): HydrationDiffNode {
9194
children: [],
9295
serverProps: undefined,
9396
serverTail: [],
97+
distanceFromLeaf: distanceFromLeaf,
9498
};
9599
} else if (hydrationDiffRootDEV.fiber !== fiber) {
96100
throw new Error(
97101
'Saw multiple hydration diff roots in a pass. This is a bug in React.',
98102
);
103+
} else if (hydrationDiffRootDEV.distanceFromLeaf > distanceFromLeaf) {
104+
hydrationDiffRootDEV.distanceFromLeaf = distanceFromLeaf;
99105
}
100106
return hydrationDiffRootDEV;
101107
}
102-
const siblings = buildHydrationDiffNode(fiber.return).children;
108+
const siblings = buildHydrationDiffNode(
109+
fiber.return,
110+
distanceFromLeaf + 1,
111+
).children;
103112
// The same node may already exist in the parent. Since we currently always render depth first
104113
// and rerender if we suspend or terminate early, if a shared ancestor was added we should still
105114
// be inside of that shared ancestor which means it was the last one to be added. If this changes
106115
// we may have to scan the whole set.
107116
if (siblings.length > 0 && siblings[siblings.length - 1].fiber === fiber) {
108-
return siblings[siblings.length - 1];
117+
const existing = siblings[siblings.length - 1];
118+
if (existing.distanceFromLeaf > distanceFromLeaf) {
119+
existing.distanceFromLeaf = distanceFromLeaf;
120+
}
121+
return existing;
109122
}
110123
const newNode: HydrationDiffNode = {
111124
fiber: fiber,
112125
children: [],
113126
serverProps: undefined,
114127
serverTail: [],
128+
distanceFromLeaf: distanceFromLeaf,
115129
};
116130
siblings.push(newNode);
117131
return newNode;
@@ -202,7 +216,7 @@ function warnNonHydratedInstance(
202216
}
203217

204218
// Add this fiber to the diff tree.
205-
const diffNode = buildHydrationDiffNode(fiber);
219+
const diffNode = buildHydrationDiffNode(fiber, 0);
206220
// We use null as a signal that there was no node to match.
207221
diffNode.serverProps = null;
208222
if (rejectedCandidate !== null) {
@@ -429,7 +443,7 @@ function prepareToHydrateHostInstance(
429443
hostContext,
430444
);
431445
if (differences !== null) {
432-
const diffNode = buildHydrationDiffNode(fiber);
446+
const diffNode = buildHydrationDiffNode(fiber, 0);
433447
diffNode.serverProps = differences;
434448
}
435449
}
@@ -473,7 +487,7 @@ function prepareToHydrateHostTextInstance(fiber: Fiber): void {
473487
parentProps,
474488
);
475489
if (difference !== null) {
476-
const diffNode = buildHydrationDiffNode(fiber);
490+
const diffNode = buildHydrationDiffNode(fiber, 0);
477491
diffNode.serverProps = difference;
478492
}
479493
}
@@ -491,7 +505,7 @@ function prepareToHydrateHostTextInstance(fiber: Fiber): void {
491505
parentProps,
492506
);
493507
if (difference !== null) {
494-
const diffNode = buildHydrationDiffNode(fiber);
508+
const diffNode = buildHydrationDiffNode(fiber, 0);
495509
diffNode.serverProps = difference;
496510
}
497511
}
@@ -645,13 +659,14 @@ function warnIfUnhydratedTailNodes(fiber: Fiber) {
645659
if (__DEV__) {
646660
let nextInstance = nextHydratableInstance;
647661
while (nextInstance) {
648-
const diffNode = buildHydrationDiffNode(fiber);
662+
const diffNode = buildHydrationDiffNode(fiber, 0);
649663
const description =
650664
describeHydratableInstanceForDevWarnings(nextInstance);
651665
diffNode.serverTail.push(description);
652666
if (description.type === 'Suspense') {
667+
const suspenseInstance: SuspenseInstance = (nextInstance: any);
653668
nextInstance =
654-
getNextHydratableInstanceAfterSuspenseInstance(nextInstance);
669+
getNextHydratableInstanceAfterSuspenseInstance(suspenseInstance);
655670
} else {
656671
nextInstance = getNextHydratableSibling(nextInstance);
657672
}

packages/react-reconciler/src/ReactFiberHydrationDiffs.js

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,28 @@ export type HydrationDiffNode = {
3838
| $ReadOnly<{type: string, props: $ReadOnly<{[propName: string]: mixed}>}>
3939
| string,
4040
>,
41+
distanceFromLeaf: number,
4142
};
4243

4344
const maxRowLength = 120;
45+
const idealDepth = 15;
4446

45-
function shouldCollapse(node: HydrationDiffNode): null | HydrationDiffNode {
46-
return null;
47+
function findNotableNode(
48+
node: HydrationDiffNode,
49+
indent: number,
50+
): HydrationDiffNode {
51+
if (
52+
node.serverProps === undefined &&
53+
node.serverTail.length === 0 &&
54+
node.children.length === 1 &&
55+
node.distanceFromLeaf > 3 &&
56+
node.distanceFromLeaf > idealDepth - indent
57+
) {
58+
// This is not an interesting node for contextual purposes so we can skip it.
59+
const child = node.children[0];
60+
return findNotableNode(child, indent);
61+
}
62+
return node;
4763
}
4864

4965
function indentation(indent: number): string {
@@ -509,8 +525,11 @@ function describeSiblingFiber(fiber: Fiber, indent: number): string {
509525
}
510526

511527
function describeNode(node: HydrationDiffNode, indent: number): string {
512-
const skipToNode = shouldCollapse(node);
513-
if (skipToNode !== null) {
528+
const skipToNode = findNotableNode(node, indent);
529+
if (
530+
skipToNode !== node &&
531+
(node.children.length !== 1 || node.children[0] !== skipToNode)
532+
) {
514533
return indentation(indent) + '...\n' + describeNode(skipToNode, indent + 1);
515534
}
516535

0 commit comments

Comments
 (0)