Skip to content

Commit 1229123

Browse files
committed
Tighten up the types of getFirstHydratableChild
We currently call getFirstHydratableChild to step into the children of a suspense boundary. This can be a text node or a suspense boundary which isn't compatible with getFirstHydratableChild, and we cheat the type. This accidentally works because .firstChild always returns null on those nodes in the DOM. This just makes that explicit.
1 parent a5062b1 commit 1229123

File tree

2 files changed

+22
-12
lines changed

2 files changed

+22
-12
lines changed

packages/react-reconciler/src/ReactFiberHydrationContext.new.js

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,8 @@ function tryHydrate(fiber, nextInstance) {
261261
const instance = canHydrateInstance(nextInstance, type, props);
262262
if (instance !== null) {
263263
fiber.stateNode = (instance: Instance);
264+
hydrationParentFiber = fiber;
265+
nextHydratableInstance = getFirstHydratableChild(instance);
264266
return true;
265267
}
266268
return false;
@@ -270,6 +272,9 @@ function tryHydrate(fiber, nextInstance) {
270272
const textInstance = canHydrateTextInstance(nextInstance, text);
271273
if (textInstance !== null) {
272274
fiber.stateNode = (textInstance: TextInstance);
275+
hydrationParentFiber = fiber;
276+
// Text Instances don't have children so there's nothing to hydrate.
277+
nextHydratableInstance = null;
273278
return true;
274279
}
275280
return false;
@@ -294,6 +299,10 @@ function tryHydrate(fiber, nextInstance) {
294299
);
295300
dehydratedFragment.return = fiber;
296301
fiber.child = dehydratedFragment;
302+
hydrationParentFiber = fiber;
303+
// While a Suspense Instance does have children, we won't step into
304+
// it during the first pass. Instead, we'll reenter it later.
305+
nextHydratableInstance = null;
297306
return true;
298307
}
299308
}
@@ -322,6 +331,7 @@ function tryToClaimNextHydratableInstance(fiber: Fiber): void {
322331
// We use this as a heuristic. It's based on intuition and not data so it
323332
// might be flawed or unnecessary.
324333
nextInstance = getNextHydratableSibling(firstAttemptedInstance);
334+
const prevHydrationParentFiber: Fiber = (hydrationParentFiber: any);
325335
if (!nextInstance || !tryHydrate(fiber, nextInstance)) {
326336
// Nothing to hydrate. Make it an insertion.
327337
insertNonHydratedInstance((hydrationParentFiber: any), fiber);
@@ -333,13 +343,8 @@ function tryToClaimNextHydratableInstance(fiber: Fiber): void {
333343
// superfluous and we'll delete it. Since we can't eagerly delete it
334344
// we'll have to schedule a deletion. To do that, this node needs a dummy
335345
// fiber associated with it.
336-
deleteHydratableInstance(
337-
(hydrationParentFiber: any),
338-
firstAttemptedInstance,
339-
);
346+
deleteHydratableInstance(prevHydrationParentFiber, firstAttemptedInstance);
340347
}
341-
hydrationParentFiber = fiber;
342-
nextHydratableInstance = getFirstHydratableChild((nextInstance: any));
343348
}
344349

345350
function prepareToHydrateHostInstance(

packages/react-reconciler/src/ReactFiberHydrationContext.old.js

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,8 @@ function tryHydrate(fiber, nextInstance) {
261261
const instance = canHydrateInstance(nextInstance, type, props);
262262
if (instance !== null) {
263263
fiber.stateNode = (instance: Instance);
264+
hydrationParentFiber = fiber;
265+
nextHydratableInstance = getFirstHydratableChild(instance);
264266
return true;
265267
}
266268
return false;
@@ -270,6 +272,9 @@ function tryHydrate(fiber, nextInstance) {
270272
const textInstance = canHydrateTextInstance(nextInstance, text);
271273
if (textInstance !== null) {
272274
fiber.stateNode = (textInstance: TextInstance);
275+
hydrationParentFiber = fiber;
276+
// Text Instances don't have children so there's nothing to hydrate.
277+
nextHydratableInstance = null;
273278
return true;
274279
}
275280
return false;
@@ -294,6 +299,10 @@ function tryHydrate(fiber, nextInstance) {
294299
);
295300
dehydratedFragment.return = fiber;
296301
fiber.child = dehydratedFragment;
302+
hydrationParentFiber = fiber;
303+
// While a Suspense Instance does have children, we won't step into
304+
// it during the first pass. Instead, we'll reenter it later.
305+
nextHydratableInstance = null;
297306
return true;
298307
}
299308
}
@@ -322,6 +331,7 @@ function tryToClaimNextHydratableInstance(fiber: Fiber): void {
322331
// We use this as a heuristic. It's based on intuition and not data so it
323332
// might be flawed or unnecessary.
324333
nextInstance = getNextHydratableSibling(firstAttemptedInstance);
334+
const prevHydrationParentFiber: Fiber = (hydrationParentFiber: any);
325335
if (!nextInstance || !tryHydrate(fiber, nextInstance)) {
326336
// Nothing to hydrate. Make it an insertion.
327337
insertNonHydratedInstance((hydrationParentFiber: any), fiber);
@@ -333,13 +343,8 @@ function tryToClaimNextHydratableInstance(fiber: Fiber): void {
333343
// superfluous and we'll delete it. Since we can't eagerly delete it
334344
// we'll have to schedule a deletion. To do that, this node needs a dummy
335345
// fiber associated with it.
336-
deleteHydratableInstance(
337-
(hydrationParentFiber: any),
338-
firstAttemptedInstance,
339-
);
346+
deleteHydratableInstance(prevHydrationParentFiber, firstAttemptedInstance);
340347
}
341-
hydrationParentFiber = fiber;
342-
nextHydratableInstance = getFirstHydratableChild((nextInstance: any));
343348
}
344349

345350
function prepareToHydrateHostInstance(

0 commit comments

Comments
 (0)