@@ -275,7 +275,7 @@ type SuspenseNode = {
275275 parent : null | SuspenseNode ,
276276 firstChild : null | SuspenseNode ,
277277 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.
279279 // Track whether any of the items in suspendedBy are unique this this Suspense boundaries or if they're all
280280 // also in the parent sets. This determine whether this could contribute in the loading sequence.
281281 hasUniqueSuspenders : boolean ,
@@ -2437,37 +2437,40 @@ export function attach(
24372437 parentSuspenseNode = parentSuspenseNode.parent;
24382438 }
24392439 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+ );
24612445 }
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;
24692464 }
24702465 }
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+ }
24712474 }
24722475
24732476 function getAwaitInSuspendedByFromIO(
0 commit comments