Skip to content

Commit

Permalink
[DevTools] Remove findCurrentFiberUsingSlowPathByFiberInstance (#30818)
Browse files Browse the repository at this point in the history
We always track the last committed Fiber on `FiberInstance.data`.


https://github.com/facebook/react/blob/dcae56f8b72f625d8affe5729ca9991b31a492ac/packages/react-devtools-shared/src/backend/fiber/renderer.js#L3068

So we can now remove this complex slow path to get the current fiber.
  • Loading branch information
sebmarkbage authored Aug 27, 2024
1 parent 1a8f92a commit 9690b9a
Showing 1 changed file with 7 additions and 214 deletions.
221 changes: 7 additions & 214 deletions packages/react-devtools-shared/src/backend/fiber/renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -3550,7 +3550,7 @@ export function attach(
fiberInstance: FiberInstance,
): $ReadOnlyArray<HostInstance> {
const hostInstances = [];
const fiber = findCurrentFiberUsingSlowPathByFiberInstance(fiberInstance);
const fiber = fiberInstance.data;
if (!fiber) {
return hostInstances;
}
Expand Down Expand Up @@ -3601,8 +3601,7 @@ export function attach(
// TODO: Handle VirtualInstance.
return null;
}
const fiber =
findCurrentFiberUsingSlowPathByFiberInstance(devtoolsInstance);
const fiber = devtoolsInstance.data;
if (fiber === null) {
return null;
}
Expand Down Expand Up @@ -3710,208 +3709,6 @@ export function attach(
return null;
}

// This function is copied from React and should be kept in sync:
// https://github.com/facebook/react/blob/main/packages/react-reconciler/src/ReactFiberTreeReflection.js
function assertIsMounted(fiber: Fiber) {
if (getNearestMountedFiber(fiber) !== fiber) {
throw new Error('Unable to find node on an unmounted component.');
}
}

// This function is copied from React and should be kept in sync:
// https://github.com/facebook/react/blob/main/packages/react-reconciler/src/ReactFiberTreeReflection.js
function getNearestMountedFiber(fiber: Fiber): null | Fiber {
let node = fiber;
let nearestMounted: null | Fiber = fiber;
if (!fiber.alternate) {
// If there is no alternate, this might be a new tree that isn't inserted
// yet. If it is, then it will have a pending insertion effect on it.
let nextNode: Fiber = node;
do {
node = nextNode;
// TODO: This function, and these flags, are a leaked implementation
// detail. Once we start releasing DevTools in lockstep with React, we
// should import a function from the reconciler instead.
const Placement = 0b000000000000000000000000010;
const Hydrating = 0b000000000000001000000000000;
if ((node.flags & (Placement | Hydrating)) !== 0) {
// This is an insertion or in-progress hydration. The nearest possible
// mounted fiber is the parent but we need to continue to figure out
// if that one is still mounted.
nearestMounted = node.return;
}
// $FlowFixMe[incompatible-type] we bail out when we get a null
nextNode = node.return;
} while (nextNode);
} else {
while (node.return) {
node = node.return;
}
}
if (node.tag === HostRoot) {
// TODO: Check if this was a nested HostRoot when used with
// renderContainerIntoSubtree.
return nearestMounted;
}
// If we didn't hit the root, that means that we're in an disconnected tree
// that has been unmounted.
return null;
}

// This function is copied from React and should be kept in sync:
// https://github.com/facebook/react/blob/main/packages/react-reconciler/src/ReactFiberTreeReflection.js
// It would be nice if we updated React to inject this function directly (vs just indirectly via findDOMNode).
// BEGIN copied code
function findCurrentFiberUsingSlowPathByFiberInstance(
fiberInstance: FiberInstance,
): Fiber | null {
const fiber = fiberInstance.data;
const alternate = fiber.alternate;
if (!alternate) {
// If there is no alternate, then we only need to check if it is mounted.
const nearestMounted = getNearestMountedFiber(fiber);

if (nearestMounted === null) {
throw new Error('Unable to find node on an unmounted component.');
}

if (nearestMounted !== fiber) {
return null;
}
return fiber;
}
// If we have two possible branches, we'll walk backwards up to the root
// to see what path the root points to. On the way we may hit one of the
// special cases and we'll deal with them.
let a: Fiber = fiber;
let b: Fiber = alternate;
while (true) {
const parentA = a.return;
if (parentA === null) {
// We're at the root.
break;
}
const parentB = parentA.alternate;
if (parentB === null) {
// There is no alternate. This is an unusual case. Currently, it only
// happens when a Suspense component is hidden. An extra fragment fiber
// is inserted in between the Suspense fiber and its children. Skip
// over this extra fragment fiber and proceed to the next parent.
const nextParent = parentA.return;
if (nextParent !== null) {
a = b = nextParent;
continue;
}
// If there's no parent, we're at the root.
break;
}

// If both copies of the parent fiber point to the same child, we can
// assume that the child is current. This happens when we bailout on low
// priority: the bailed out fiber's child reuses the current child.
if (parentA.child === parentB.child) {
let child = parentA.child;
while (child) {
if (child === a) {
// We've determined that A is the current branch.
assertIsMounted(parentA);
return fiber;
}
if (child === b) {
// We've determined that B is the current branch.
assertIsMounted(parentA);
return alternate;
}
child = child.sibling;
}

// We should never have an alternate for any mounting node. So the only
// way this could possibly happen is if this was unmounted, if at all.
throw new Error('Unable to find node on an unmounted component.');
}

if (a.return !== b.return) {
// The return pointer of A and the return pointer of B point to different
// fibers. We assume that return pointers never criss-cross, so A must
// belong to the child set of A.return, and B must belong to the child
// set of B.return.
a = parentA;
b = parentB;
} else {
// The return pointers point to the same fiber. We'll have to use the
// default, slow path: scan the child sets of each parent alternate to see
// which child belongs to which set.
//
// Search parent A's child set
let didFindChild = false;
let child = parentA.child;
while (child) {
if (child === a) {
didFindChild = true;
a = parentA;
b = parentB;
break;
}
if (child === b) {
didFindChild = true;
b = parentA;
a = parentB;
break;
}
child = child.sibling;
}
if (!didFindChild) {
// Search parent B's child set
child = parentB.child;
while (child) {
if (child === a) {
didFindChild = true;
a = parentB;
b = parentA;
break;
}
if (child === b) {
didFindChild = true;
b = parentB;
a = parentA;
break;
}
child = child.sibling;
}

if (!didFindChild) {
throw new Error(
'Child was not found in either parent set. This indicates a bug ' +
'in React related to the return pointer. Please file an issue.',
);
}
}
}

if (a.alternate !== b) {
throw new Error(
"Return fibers should always be each others' alternates. " +
'This error is likely caused by a bug in React. Please file an issue.',
);
}
}

// If the root is not a host container, we're in a disconnected tree. I.e.
// unmounted.
if (a.tag !== HostRoot) {
throw new Error('Unable to find node on an unmounted component.');
}

if (a.stateNode.current === a) {
// We've determined that A is the current branch.
return fiber;
}
// Otherwise B has to be current branch.
return alternate;
}

// END copied code

function getElementAttributeByPath(
id: number,
path: Array<string | number>,
Expand Down Expand Up @@ -4096,8 +3893,7 @@ export function attach(
return {instance, style};
}

const fiber =
findCurrentFiberUsingSlowPathByFiberInstance(devtoolsInstance);
const fiber = devtoolsInstance.data;
if (fiber !== null) {
instance = fiber.stateNode;

Expand Down Expand Up @@ -4153,7 +3949,7 @@ export function attach(
function inspectFiberInstanceRaw(
fiberInstance: FiberInstance,
): InspectedElement | null {
const fiber = findCurrentFiberUsingSlowPathByFiberInstance(fiberInstance);
const fiber = fiberInstance.data;
if (fiber == null) {
return null;
}
Expand Down Expand Up @@ -4913,8 +4709,7 @@ export function attach(
// TODO: Handle VirtualInstance.
return;
}
const fiber =
findCurrentFiberUsingSlowPathByFiberInstance(devtoolsInstance);
const fiber = devtoolsInstance.data;
if (fiber !== null) {
const instance = fiber.stateNode;

Expand Down Expand Up @@ -4979,8 +4774,7 @@ export function attach(
// TODO: Handle VirtualInstance.
return;
}
const fiber =
findCurrentFiberUsingSlowPathByFiberInstance(devtoolsInstance);
const fiber = devtoolsInstance.data;
if (fiber !== null) {
const instance = fiber.stateNode;

Expand Down Expand Up @@ -5055,8 +4849,7 @@ export function attach(
// TODO: Handle VirtualInstance.
return;
}
const fiber =
findCurrentFiberUsingSlowPathByFiberInstance(devtoolsInstance);
const fiber = devtoolsInstance.data;
if (fiber !== null) {
const instance = fiber.stateNode;

Expand Down

0 comments on commit 9690b9a

Please sign in to comment.