Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DevTools] Compute new reordered child set from the instance tree #30668

Merged
merged 1 commit into from
Aug 13, 2024
Merged
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
69 changes: 16 additions & 53 deletions packages/react-devtools-shared/src/backend/fiber/renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -2566,24 +2566,28 @@ export function attach(
}
}

function recordResetChildren(
parentInstance: DevToolsInstance,
childSet: Fiber,
) {
function recordResetChildren(parentInstance: DevToolsInstance) {
if (__DEBUG__) {
debug('recordResetChildren()', childSet, parentInstance);
if (
parentInstance.firstChild !== null &&
parentInstance.firstChild.kind === FIBER_INSTANCE
) {
debug(
'recordResetChildren()',
parentInstance.firstChild.data,
parentInstance,
);
}
}
// The frontend only really cares about the displayName, key, and children.
// The first two don't really change, so we are only concerned with the order of children here.
// This is trickier than a simple comparison though, since certain types of fibers are filtered.
const nextChildren: Array<number> = [];

// This is a naive implementation that shallowly recourses children.
// We might want to revisit this if it proves to be too inefficient.
let child: null | Fiber = childSet;
let child: null | DevToolsInstance = parentInstance.firstChild;
while (child !== null) {
findReorderedChildrenRecursively(child, nextChildren);
child = child.sibling;
nextChildren.push(child.id);
child = child.nextSibling;
}

const numChildren = nextChildren.length;
Expand All @@ -2599,38 +2603,6 @@ export function attach(
}
}

function findReorderedChildrenRecursively(
fiber: Fiber,
nextChildren: Array<number>,
) {
if (!shouldFilterFiber(fiber)) {
nextChildren.push(getFiberIDThrows(fiber));
} else {
let child = fiber.child;
const isTimedOutSuspense =
fiber.tag === SuspenseComponent && fiber.memoizedState !== null;
if (isTimedOutSuspense) {
// Special case: if Suspense mounts in a timed-out state,
// get the fallback child from the inner fragment,
// and skip over the primary child.
const primaryChildFragment = fiber.child;
const fallbackChildFragment = primaryChildFragment
? primaryChildFragment.sibling
: null;
const fallbackChild = fallbackChildFragment
? fallbackChildFragment.child
: null;
if (fallbackChild !== null) {
child = fallbackChild;
}
}
while (child !== null) {
findReorderedChildrenRecursively(child, nextChildren);
child = child.sibling;
}
}
}

// Returns whether closest unfiltered fiber parent needs to reset its child list.
function updateChildrenRecursively(
nextFirstChild: null | Fiber,
Expand Down Expand Up @@ -2914,17 +2886,8 @@ export function attach(
// We need to crawl the subtree for closest non-filtered Fibers
// so that we can display them in a flat children set.
if (shouldIncludeInTree) {
// Normally, search for children from the rendered child.
let nextChildSet = nextFiber.child;
if (nextDidTimeOut) {
// Special case: timed-out Suspense renders the fallback set.
const nextFiberChild = nextFiber.child;
nextChildSet = nextFiberChild ? nextFiberChild.sibling : null;
}
if (nextChildSet != null) {
if (reconcilingParent !== null) {
recordResetChildren(reconcilingParent, nextChildSet);
}
if (reconcilingParent !== null) {
recordResetChildren(reconcilingParent);
}
// We've handled the child order change for this Fiber.
// Since it's included, there's no need to invalidate parent child order.
Expand Down
Loading