Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 46 additions & 12 deletions packages/react-devtools-shared/src/backend/fiber/renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -2139,8 +2139,8 @@ export function attach(
// Regular operations
pendingOperations.length +
// All suspender changes are batched in a single message.
// [SUSPENSE_TREE_OPERATION_SUSPENDERS, suspenderChangesLength, ...[id, hasUniqueSuspenders]]
(numSuspenderChanges > 0 ? 2 + numSuspenderChanges * 2 : 0),
// [SUSPENSE_TREE_OPERATION_SUSPENDERS, suspenderChangesLength, ...[id, hasUniqueSuspenders, isSuspended]]
(numSuspenderChanges > 0 ? 2 + numSuspenderChanges * 3 : 0),
);

// Identify which renderer this update is coming from.
Expand Down Expand Up @@ -2225,6 +2225,14 @@ export function attach(
}
operations[i++] = fiberIdWithChanges;
operations[i++] = suspense.hasUniqueSuspenders ? 1 : 0;
const instance = suspense.instance;
const isSuspended =
// TODO: Track if other SuspenseNode like SuspenseList rows are suspended.
(instance.kind === FIBER_INSTANCE ||
instance.kind === FILTERED_FIBER_INSTANCE) &&
instance.data.tag === SuspenseComponent &&
instance.data.memoizedState !== null;
operations[i++] = isSuspended ? 1 : 0;
operations[i++] = suspense.environments.size;
suspense.environments.forEach((count, env) => {
operations[i++] = getStringID(env);
Expand Down Expand Up @@ -2640,9 +2648,15 @@ export function attach(
const fiber = fiberInstance.data;
const props = fiber.memoizedProps;
// TODO: Compute a fallback name based on Owner, key etc.
const name = props === null ? null : props.name || null;
const name =
fiber.tag !== SuspenseComponent || props === null
? null
: props.name || null;
const nameStringID = getStringID(name);

const isSuspended =
fiber.tag === SuspenseComponent && fiber.memoizedState !== null;

if (__DEBUG__) {
console.log('recordSuspenseMount()', suspenseInstance);
}
Expand All @@ -2653,6 +2667,7 @@ export function attach(
pushOperation(fiberID);
pushOperation(parentID);
pushOperation(nameStringID);
pushOperation(isSuspended ? 1 : 0);

const rects = suspenseInstance.rects;
if (rects === null) {
Expand Down Expand Up @@ -5006,15 +5021,24 @@ export function attach(
const nextIsSuspended = isSuspendedOffscreen(nextFiber);

if (isLegacySuspense) {
if (
fiberInstance !== null &&
fiberInstance.suspenseNode !== null &&
(prevFiber.stateNode === null) !== (nextFiber.stateNode === null)
) {
trackThrownPromisesFromRetryCache(
fiberInstance.suspenseNode,
nextFiber.stateNode,
);
if (fiberInstance !== null && fiberInstance.suspenseNode !== null) {
const suspenseNode = fiberInstance.suspenseNode;
if (
(prevFiber.stateNode === null) !==
(nextFiber.stateNode === null)
) {
trackThrownPromisesFromRetryCache(
suspenseNode,
nextFiber.stateNode,
);
}
if (
(prevFiber.memoizedState === null) !==
(nextFiber.memoizedState === null)
) {
// Toggle suspended state.
recordSuspenseSuspenders(suspenseNode);
}
}
}
// The logic below is inspired by the code paths in updateSuspenseComponent()
Expand Down Expand Up @@ -5162,6 +5186,14 @@ export function attach(
);
}

if (
(prevFiber.memoizedState === null) !==
(nextFiber.memoizedState === null)
) {
// Toggle suspended state.
recordSuspenseSuspenders(suspenseNode);
}

shouldMeasureSuspenseNode = false;
updateFlags |= updateSuspenseChildrenRecursively(
nextContentFiber,
Expand All @@ -5188,6 +5220,8 @@ export function attach(
}

trackThrownPromisesFromRetryCache(suspenseNode, nextFiber.stateNode);
// Toggle suspended state.
recordSuspenseSuspenders(suspenseNode);

mountSuspenseChildrenRecursively(
nextContentFiber,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,7 @@ export function attach(
pushOperation(id);
pushOperation(parentID);
pushOperation(getStringID(null)); // name
pushOperation(0); // isSuspended
// TODO: Measure rect of root
pushOperation(-1);
} else {
Expand Down
8 changes: 6 additions & 2 deletions packages/react-devtools-shared/src/devtools/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -1552,7 +1552,8 @@ export default class Store extends EventEmitter<{
const id = operations[i + 1];
const parentID = operations[i + 2];
const nameStringID = operations[i + 3];
const numRects = ((operations[i + 4]: any): number);
const isSuspended = operations[i + 4] === 1;
const numRects = ((operations[i + 5]: any): number);
let name = stringTable[nameStringID];

if (this._idToSuspense.has(id)) {
Expand All @@ -1579,7 +1580,7 @@ export default class Store extends EventEmitter<{
}
}

i += 5;
i += 6;
let rects: SuspenseNode['rects'];
if (numRects === -1) {
rects = null;
Expand Down Expand Up @@ -1625,6 +1626,7 @@ export default class Store extends EventEmitter<{
name,
rects,
hasUniqueSuspenders: false,
isSuspended: isSuspended,
});

hasSuspenseTreeChanged = true;
Expand Down Expand Up @@ -1801,6 +1803,7 @@ export default class Store extends EventEmitter<{
for (let changeIndex = 0; changeIndex < changeLength; changeIndex++) {
const id = operations[i++];
const hasUniqueSuspenders = operations[i++] === 1;
const isSuspended = operations[i++] === 1;
const environmentNamesLength = operations[i++];
const environmentNames = [];
for (
Expand Down Expand Up @@ -1832,6 +1835,7 @@ export default class Store extends EventEmitter<{
}

suspense.hasUniqueSuspenders = hasUniqueSuspenders;
suspense.isSuspended = isSuspended;
// TODO: Recompute the environment names.
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,8 @@ function updateTree(
const fiberID = operations[i + 1];
const parentID = operations[i + 2];
const nameStringID = operations[i + 3];
const numRects = operations[i + 4];
const isSuspended = operations[i + 4];
const numRects = operations[i + 5];
const name = stringTable[nameStringID];

if (__DEBUG__) {
Expand All @@ -388,16 +389,16 @@ function updateTree(
} else {
rects =
'[' +
operations.slice(i + 5, i + 5 + numRects * 4).join(',') +
operations.slice(i + 6, i + 6 + numRects * 4).join(',') +
']';
}
debug(
'Add suspense',
`node ${fiberID} (name=${JSON.stringify(name)}, rects={${rects}}) under ${parentID}`,
`node ${fiberID} (name=${JSON.stringify(name)}, rects={${rects}}) under ${parentID} suspended ${isSuspended}`,
);
}

i += 5 + (numRects === -1 ? 0 : numRects * 4);
i += 6 + (numRects === -1 ? 0 : numRects * 4);
break;
}

Expand Down Expand Up @@ -459,12 +460,13 @@ function updateTree(
for (let changeIndex = 0; changeIndex < changeLength; changeIndex++) {
const suspenseNodeId = operations[i++];
const hasUniqueSuspenders = operations[i++] === 1;
const isSuspended = operations[i++] === 1;
const environmentNamesLength = operations[i++];
i += environmentNamesLength;
if (__DEBUG__) {
debug(
'Suspender changes',
`Suspense node ${suspenseNodeId} unique suspenders set to ${String(hasUniqueSuspenders)} with ${String(environmentNamesLength)} environments`,
`Suspense node ${suspenseNodeId} unique suspenders set to ${String(hasUniqueSuspenders)} is suspended set to ${String(isSuspended)} with ${String(environmentNamesLength)} environments`,
);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@
outline-width: 0;
}

.SuspenseRectsScaledRect[data-suspended='true'] {
opacity: 0.3;
}

/* highlight this boundary */
.SuspenseRectsBoundary:hover:not(:has(.SuspenseRectsBoundary:hover)) > .SuspenseRectsRect, .SuspenseRectsBoundary[data-highlighted='true'] > .SuspenseRectsRect {
background-color: var(--color-background-hover);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,13 @@ function ScaledRect({
className,
rect,
visible,
suspended,
...props
}: {
className: string,
rect: Rect,
visible: boolean,
suspended: boolean,
...
}): React$Node {
const viewBox = useContext(ViewBox);
Expand All @@ -53,6 +55,7 @@ function ScaledRect({
{...props}
className={styles.SuspenseRectsScaledRect + ' ' + className}
data-visible={visible}
data-suspended={suspended}
style={{
width,
height,
Expand Down Expand Up @@ -145,7 +148,8 @@ function SuspenseRects({
<ScaledRect
rect={boundingBox}
className={styles.SuspenseRectsBoundary}
visible={visible}>
visible={visible}
suspended={suspense.isSuspended}>
<ViewBox.Provider value={boundingBox}>
{visible &&
suspense.rects !== null &&
Expand Down
1 change: 1 addition & 0 deletions packages/react-devtools-shared/src/frontend/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ export type SuspenseNode = {
name: string | null,
rects: null | Array<Rect>,
hasUniqueSuspenders: boolean,
isSuspended: boolean,
};

// Serialized version of ReactIOInfo
Expand Down
10 changes: 6 additions & 4 deletions packages/react-devtools-shared/src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -340,9 +340,10 @@ export function printOperationsArray(operations: Array<number>) {
const fiberID = operations[i + 1];
const parentID = operations[i + 2];
const nameStringID = operations[i + 3];
const numRects = operations[i + 4];
const isSuspended = operations[i + 4];
const numRects = operations[i + 5];

i += 5;
i += 6;

const name = stringTable[nameStringID];
let rects: string;
Expand All @@ -368,7 +369,7 @@ export function printOperationsArray(operations: Array<number>) {
}

logs.push(
`Add suspense node ${fiberID} (${String(name)},rects={${rects}}) under ${parentID}`,
`Add suspense node ${fiberID} (${String(name)},rects={${rects}}) under ${parentID} suspended ${isSuspended}`,
);
break;
}
Expand Down Expand Up @@ -431,10 +432,11 @@ export function printOperationsArray(operations: Array<number>) {
for (let changeIndex = 0; changeIndex < changeLength; changeIndex++) {
const id = operations[i++];
const hasUniqueSuspenders = operations[i++] === 1;
const isSuspended = operations[i++] === 1;
const environmentNamesLength = operations[i++];
i += environmentNamesLength;
logs.push(
`Suspense node ${id} unique suspenders set to ${String(hasUniqueSuspenders)} with ${String(environmentNamesLength)} environments`,
`Suspense node ${id} unique suspenders set to ${String(hasUniqueSuspenders)} is suspended set to ${String(isSuspended)} with ${String(environmentNamesLength)} environments`,
);
}

Expand Down
Loading