Skip to content

Commit afcb9cd

Browse files
author
Juan
authored
[DevTools] Update Fiber logic in backend renderer to match implementation in React (#22527)
* [DevTools] Update isMountedImpl to match implementation in React * Also sync findCurrentFiberUsingSlowPathById
1 parent 20ca9b5 commit afcb9cd

File tree

1 file changed

+40
-54
lines changed

1 file changed

+40
-54
lines changed

packages/react-devtools-shared/src/backend/renderer.js

+40-54
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ type ReactTypeOfSideEffectType = {|
128128
PerformedWork: number,
129129
Placement: number,
130130
Incomplete: number,
131+
Hydrating: number,
131132
|};
132133

133134
function getFiberFlags(fiber: Fiber): number {
@@ -156,6 +157,7 @@ export function getInternalReactConstants(
156157
PerformedWork: 0b01,
157158
Placement: 0b10,
158159
Incomplete: 0b10000000000000,
160+
Hydrating: 0b1000000000000,
159161
};
160162

161163
// **********************************************************
@@ -526,7 +528,7 @@ export function attach(
526528
} = getInternalReactConstants(version);
527529
const {
528530
DidCapture,
529-
Incomplete,
531+
Hydrating,
530532
NoFlags,
531533
PerformedWork,
532534
Placement,
@@ -2707,51 +2709,33 @@ export function attach(
27072709
return null;
27082710
}
27092711

2710-
const MOUNTING = 1;
2711-
const MOUNTED = 2;
2712-
const UNMOUNTED = 3;
2712+
// This function is copied from React and should be kept in sync:
2713+
// https://github.com/facebook/react/blob/main/packages/react-reconciler/src/ReactFiberTreeReflection.js
2714+
function assertIsMounted(fiber) {
2715+
if (getNearestMountedFiber(fiber) !== fiber) {
2716+
throw new Error('Unable to find node on an unmounted component.');
2717+
}
2718+
}
27132719

27142720
// This function is copied from React and should be kept in sync:
27152721
// https://github.com/facebook/react/blob/main/packages/react-reconciler/src/ReactFiberTreeReflection.js
2716-
function isFiberMountedImpl(fiber: Fiber): number {
2722+
function getNearestMountedFiber(fiber: Fiber): null | Fiber {
27172723
let node = fiber;
2718-
let prevNode = null;
2724+
let nearestMounted = fiber;
27192725
if (!fiber.alternate) {
27202726
// If there is no alternate, this might be a new tree that isn't inserted
27212727
// yet. If it is, then it will have a pending insertion effect on it.
2722-
if ((getFiberFlags(node) & Placement) !== NoFlags) {
2723-
return MOUNTING;
2724-
}
2725-
// This indicates an error during render.
2726-
if ((getFiberFlags(node) & Incomplete) !== NoFlags) {
2727-
return UNMOUNTED;
2728-
}
2729-
while (node.return) {
2730-
prevNode = node;
2731-
node = node.return;
2732-
2733-
if ((getFiberFlags(node) & Placement) !== NoFlags) {
2734-
return MOUNTING;
2735-
}
2736-
// This indicates an error during render.
2737-
if ((getFiberFlags(node) & Incomplete) !== NoFlags) {
2738-
return UNMOUNTED;
2739-
}
2740-
2741-
// If this node is inside of a timed out suspense subtree, we should also ignore errors/warnings.
2742-
const isTimedOutSuspense =
2743-
node.tag === SuspenseComponent && node.memoizedState !== null;
2744-
if (isTimedOutSuspense) {
2745-
// Note that this does not include errors/warnings in the Fallback tree though!
2746-
const primaryChildFragment = node.child;
2747-
const fallbackChildFragment = primaryChildFragment
2748-
? primaryChildFragment.sibling
2749-
: null;
2750-
if (prevNode !== fallbackChildFragment) {
2751-
return UNMOUNTED;
2752-
}
2728+
let nextNode = node;
2729+
do {
2730+
node = nextNode;
2731+
if ((node.flags & (Placement | Hydrating)) !== NoFlags) {
2732+
// This is an insertion or in-progress hydration. The nearest possible
2733+
// mounted fiber is the parent but we need to continue to figure out
2734+
// if that one is still mounted.
2735+
nearestMounted = node.return;
27532736
}
2754-
}
2737+
nextNode = node.return;
2738+
} while (nextNode);
27552739
} else {
27562740
while (node.return) {
27572741
node = node.return;
@@ -2760,11 +2744,11 @@ export function attach(
27602744
if (node.tag === HostRoot) {
27612745
// TODO: Check if this was a nested HostRoot when used with
27622746
// renderContainerIntoSubtree.
2763-
return MOUNTED;
2747+
return nearestMounted;
27642748
}
27652749
// If we didn't hit the root, that means that we're in an disconnected tree
27662750
// that has been unmounted.
2767-
return UNMOUNTED;
2751+
return null;
27682752
}
27692753

27702754
// This function is copied from React and should be kept in sync:
@@ -2781,11 +2765,13 @@ export function attach(
27812765
const alternate = fiber.alternate;
27822766
if (!alternate) {
27832767
// If there is no alternate, then we only need to check if it is mounted.
2784-
const state = isFiberMountedImpl(fiber);
2785-
if (state === UNMOUNTED) {
2786-
throw Error('Unable to find node on an unmounted component.');
2768+
const nearestMounted = getNearestMountedFiber(fiber);
2769+
2770+
if (nearestMounted === null) {
2771+
throw new Error('Unable to find node on an unmounted component.');
27872772
}
2788-
if (state === MOUNTING) {
2773+
2774+
if (nearestMounted !== fiber) {
27892775
return null;
27902776
}
27912777
return fiber;
@@ -2824,23 +2810,20 @@ export function attach(
28242810
while (child) {
28252811
if (child === a) {
28262812
// We've determined that A is the current branch.
2827-
if (isFiberMountedImpl(parentA) !== MOUNTED) {
2828-
throw Error('Unable to find node on an unmounted component.');
2829-
}
2813+
assertIsMounted(parentA);
28302814
return fiber;
28312815
}
28322816
if (child === b) {
28332817
// We've determined that B is the current branch.
2834-
if (isFiberMountedImpl(parentA) !== MOUNTED) {
2835-
throw Error('Unable to find node on an unmounted component.');
2836-
}
2818+
assertIsMounted(parentA);
28372819
return alternate;
28382820
}
28392821
child = child.sibling;
28402822
}
2823+
28412824
// We should never have an alternate for any mounting node. So the only
28422825
// way this could possibly happen is if this was unmounted, if at all.
2843-
throw Error('Unable to find node on an unmounted component.');
2826+
throw new Error('Unable to find node on an unmounted component.');
28442827
}
28452828

28462829
if (a.return !== b.return) {
@@ -2891,8 +2874,9 @@ export function attach(
28912874
}
28922875
child = child.sibling;
28932876
}
2877+
28942878
if (!didFindChild) {
2895-
throw Error(
2879+
throw new Error(
28962880
'Child was not found in either parent set. This indicates a bug ' +
28972881
'in React related to the return pointer. Please file an issue.',
28982882
);
@@ -2901,17 +2885,19 @@ export function attach(
29012885
}
29022886

29032887
if (a.alternate !== b) {
2904-
throw Error(
2888+
throw new Error(
29052889
"Return fibers should always be each others' alternates. " +
29062890
'This error is likely caused by a bug in React. Please file an issue.',
29072891
);
29082892
}
29092893
}
2894+
29102895
// If the root is not a host container, we're in a disconnected tree. I.e.
29112896
// unmounted.
29122897
if (a.tag !== HostRoot) {
2913-
throw Error('Unable to find node on an unmounted component.');
2898+
throw new Error('Unable to find node on an unmounted component.');
29142899
}
2900+
29152901
if (a.stateNode.current === a) {
29162902
// We've determined that A is the current branch.
29172903
return fiber;

0 commit comments

Comments
 (0)