@samitouri / QOS-React-2 / commits / afcb9cdc93

[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;