@@ -275,7 +275,7 @@ type SuspenseNode = {
275
275
parent : null | SuspenseNode ,
276
276
firstChild : null | SuspenseNode ,
277
277
nextSibling : null | SuspenseNode ,
278
- suspendedBy : Map < ReactIOInfo , Set < DevToolsInstance | null >> , // Tracks which data we're suspended by and the children that suspend it.
278
+ suspendedBy : Map < ReactIOInfo , Set < DevToolsInstance> > , // Tracks which data we're suspended by and the children that suspend it.
279
279
// Track whether any of the items in suspendedBy are unique this this Suspense boundaries or if they're all
280
280
// also in the parent sets. This determine whether this could contribute in the loading sequence.
281
281
hasUniqueSuspenders : boolean ,
@@ -2437,37 +2437,40 @@ export function attach(
2437
2437
parentSuspenseNode = parentSuspenseNode.parent;
2438
2438
}
2439
2439
const parentInstance = reconcilingParent;
2440
- if (parentSuspenseNode !== null) {
2441
- const suspendedBy = parentSuspenseNode.suspendedBy;
2442
- const ioInfo = asyncInfo.awaited;
2443
- let suspendedBySet = suspendedBy.get(ioInfo);
2444
- if (suspendedBySet === undefined) {
2445
- suspendedBySet = new Set();
2446
- suspendedBy.set(asyncInfo.awaited, suspendedBySet);
2447
- }
2448
- // The child of the Suspense boundary that was suspended on this, or null if suspended at the root.
2449
- // This is used to keep track of how many dependents are still alive and also to get information
2450
- // like owner instances to link down into the tree.
2451
- if (!suspendedBySet.has(parentInstance)) {
2452
- suspendedBySet.add(parentInstance);
2453
- if (
2454
- !parentSuspenseNode.hasUniqueSuspenders &&
2455
- !ioExistsInSuspenseAncestor(parentSuspenseNode, ioInfo)
2456
- ) {
2457
- // This didn't exist in the parent before, so let's mark this boundary as having a unique suspender.
2458
- parentSuspenseNode.hasUniqueSuspenders = true;
2459
- }
2460
- }
2440
+ if (parentInstance === null || parentSuspenseNode === null) {
2441
+ throw new Error(
2442
+ 'It should not be possible to have suspended data outside the root. ' +
2443
+ 'Even suspending at the first position is still a child of the root.',
2444
+ );
2461
2445
}
2462
- if (parentInstance !== null) {
2463
- // Suspending at the root is not attributed to any particular component other than the SuspenseNode.
2464
- const suspendedBy = parentInstance.suspendedBy;
2465
- if (suspendedBy === null) {
2466
- parentInstance.suspendedBy = [asyncInfo];
2467
- } else if (suspendedBy.indexOf(asyncInfo) === -1) {
2468
- suspendedBy.push(asyncInfo);
2446
+ const suspenseNodeSuspendedBy = parentSuspenseNode.suspendedBy;
2447
+ const ioInfo = asyncInfo.awaited;
2448
+ let suspendedBySet = suspenseNodeSuspendedBy.get(ioInfo);
2449
+ if (suspendedBySet === undefined) {
2450
+ suspendedBySet = new Set();
2451
+ suspenseNodeSuspendedBy.set(asyncInfo.awaited, suspendedBySet);
2452
+ }
2453
+ // The child of the Suspense boundary that was suspended on this, or null if suspended at the root.
2454
+ // This is used to keep track of how many dependents are still alive and also to get information
2455
+ // like owner instances to link down into the tree.
2456
+ if (!suspendedBySet.has(parentInstance)) {
2457
+ suspendedBySet.add(parentInstance);
2458
+ if (
2459
+ !parentSuspenseNode.hasUniqueSuspenders &&
2460
+ !ioExistsInSuspenseAncestor(parentSuspenseNode, ioInfo)
2461
+ ) {
2462
+ // This didn't exist in the parent before, so let's mark this boundary as having a unique suspender.
2463
+ parentSuspenseNode.hasUniqueSuspenders = true;
2469
2464
}
2470
2465
}
2466
+ // Suspending right below the root is not attributed to any particular component in UI
2467
+ // other than the SuspenseNode and the HostRoot's FiberInstance.
2468
+ const suspendedBy = parentInstance.suspendedBy;
2469
+ if (suspendedBy === null) {
2470
+ parentInstance.suspendedBy = [asyncInfo];
2471
+ } else if (suspendedBy.indexOf(asyncInfo) === -1) {
2472
+ suspendedBy.push(asyncInfo);
2473
+ }
2471
2474
}
2472
2475
2473
2476
function getAwaitInSuspendedByFromIO(
0 commit comments