[DevTools] Update Fiber logic in backend renderer to match implementation in React (#22527)
* [DevTools] Update isMountedImpl to match implementation in React * Also sync findCurrentFiberUsingSlowPathById
Juan committed
Oct 8, 2021 at 16:19 UTC
afcb9cdc9343ddc134b03dcf4d7fbc0810b6002b
1 file changed
+40
-54
packages/react-devtools-shared/src/backend/renderer.js
+40
-54
@@ -128,6 +128,7 @@ type ReactTypeOfSideEffectType = {|
128
PerformedWork: number,
129
Placement: number,
130
Incomplete: number,
131
+ Hydrating: number,
132
|};
133
134
function getFiberFlags(fiber: Fiber): number {
@@ -156,6 +157,7 @@ export function getInternalReactConstants(
157
PerformedWork: 0b01,
158
Placement: 0b10,
159
Incomplete: 0b10000000000000,
160
+ Hydrating: 0b1000000000000,
161
};
162
163
// **********************************************************
@@ -526,7 +528,7 @@ export function attach(
528
} = getInternalReactConstants(version);
529
const {
530
DidCapture,
529
- Incomplete,
531
+ Hydrating,
532
NoFlags,
533
PerformedWork,
534
Placement,
@@ -2707,51 +2709,33 @@ export function attach(
2709
return null;
2710
}
2711
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
+ }
2719
2720
// This function is copied from React and should be kept in sync:
2721
// 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 {
2723
let node = fiber;
2718
- let prevNode = null;
2724
+ let nearestMounted = fiber;
2725
if (!fiber.alternate) {
2726
// If there is no alternate, this might be a new tree that isn't inserted
2727
// 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;
2736
}
2754
- }
2737
+ nextNode = node.return;
2738
+ } while (nextNode);
2739
} else {
2740
while (node.return) {
2741
node = node.return;
@@ -2760,11 +2744,11 @@ export function attach(
2744
if (node.tag === HostRoot) {
2745
// TODO: Check if this was a nested HostRoot when used with
2746
// renderContainerIntoSubtree.
2763
- return MOUNTED;
2747
+ return nearestMounted;
2748
}
2749
// If we didn't hit the root, that means that we're in an disconnected tree
2750
// that has been unmounted.
2767
- return UNMOUNTED;
2751
+ return null;
2752
}
2753
2754
// This function is copied from React and should be kept in sync:
@@ -2781,11 +2765,13 @@ export function attach(
2765
const alternate = fiber.alternate;
2766
if (!alternate) {
2767
// 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.');
2772
}
2788
- if (state === MOUNTING) {
2773
+
2774
+ if (nearestMounted !== fiber) {
2775
return null;
2776
}
2777
return fiber;
@@ -2824,23 +2810,20 @@ export function attach(
2810
while (child) {
2811
if (child === a) {
2812
// 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);
2814
return fiber;
2815
}
2816
if (child === b) {
2817
// 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);
2819
return alternate;
2820
}
2821
child = child.sibling;
2822
}
2823
+
2824
// We should never have an alternate for any mounting node. So the only
2825
// 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.');
2827
}
2828
2829
if (a.return !== b.return) {
@@ -2891,8 +2874,9 @@ export function attach(
2874
}
2875
child = child.sibling;
2876
}
2877
+
2878
if (!didFindChild) {
2895
- throw Error(
2879
+ throw new Error(
2880
'Child was not found in either parent set. This indicates a bug ' +
2881
'in React related to the return pointer. Please file an issue.',
2882
);
@@ -2901,17 +2885,19 @@ export function attach(
2885
}
2886
2887
if (a.alternate !== b) {
2904
- throw Error(
2888
+ throw new Error(
2889
"Return fibers should always be each others' alternates. " +
2890
'This error is likely caused by a bug in React. Please file an issue.',
2891
);
2892
}
2893
}
2894
+
2895
// If the root is not a host container, we're in a disconnected tree. I.e.
2896
// unmounted.
2897
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.');
2899
}
2900
+
2901
if (a.stateNode.current === a) {
2902
// We've determined that A is the current branch.
2903
return fiber;