[DevTools] Remove findCurrentFiberUsingSlowPathByFiberInstance (#30818)
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.
Sebastian Markbåge committed
Aug 27, 2024 at 12:05 UTC
9690b9ad749c30eab1900c99e7c25a7ed7e1d9b7
1 file changed
+7
-214
packages/react-devtools-shared/src/backend/fiber/renderer.js
+7
-214
@@ -3550,7 +3550,7 @@ export function attach(
3550
fiberInstance: FiberInstance,
3551
): $ReadOnlyArray<HostInstance> {
3552
const hostInstances = [];
3553
- const fiber = findCurrentFiberUsingSlowPathByFiberInstance(fiberInstance);
3553
+ const fiber = fiberInstance.data;
3554
if (!fiber) {
3555
return hostInstances;
3556
}
@@ -3601,8 +3601,7 @@ export function attach(
3601
// TODO: Handle VirtualInstance.
3602
return null;
3603
}
3604
- const fiber =
3605
- findCurrentFiberUsingSlowPathByFiberInstance(devtoolsInstance);
3604
+ const fiber = devtoolsInstance.data;
3605
if (fiber === null) {
3606
return null;
3607
}
@@ -3710,208 +3709,6 @@ export function attach(
3709
return null;
3710
}
3711
3713
- // This function is copied from React and should be kept in sync:
3714
- // https://github.com/facebook/react/blob/main/packages/react-reconciler/src/ReactFiberTreeReflection.js
3715
- function assertIsMounted(fiber: Fiber) {
3716
- if (getNearestMountedFiber(fiber) !== fiber) {
3717
- throw new Error('Unable to find node on an unmounted component.');
3718
- }
3719
- }
3720
-
3721
- // This function is copied from React and should be kept in sync:
3722
- // https://github.com/facebook/react/blob/main/packages/react-reconciler/src/ReactFiberTreeReflection.js
3723
- function getNearestMountedFiber(fiber: Fiber): null | Fiber {
3724
- let node = fiber;
3725
- let nearestMounted: null | Fiber = fiber;
3726
- if (!fiber.alternate) {
3727
- // If there is no alternate, this might be a new tree that isn't inserted
3728
- // yet. If it is, then it will have a pending insertion effect on it.
3729
- let nextNode: Fiber = node;
3730
- do {
3731
- node = nextNode;
3732
- // TODO: This function, and these flags, are a leaked implementation
3733
- // detail. Once we start releasing DevTools in lockstep with React, we
3734
- // should import a function from the reconciler instead.
3735
- const Placement = 0b000000000000000000000000010;
3736
- const Hydrating = 0b000000000000001000000000000;
3737
- if ((node.flags & (Placement | Hydrating)) !== 0) {
3738
- // This is an insertion or in-progress hydration. The nearest possible
3739
- // mounted fiber is the parent but we need to continue to figure out
3740
- // if that one is still mounted.
3741
- nearestMounted = node.return;
3742
- }
3743
- // $FlowFixMe[incompatible-type] we bail out when we get a null
3744
- nextNode = node.return;
3745
- } while (nextNode);
3746
- } else {
3747
- while (node.return) {
3748
- node = node.return;
3749
- }
3750
- }
3751
- if (node.tag === HostRoot) {
3752
- // TODO: Check if this was a nested HostRoot when used with
3753
- // renderContainerIntoSubtree.
3754
- return nearestMounted;
3755
- }
3756
- // If we didn't hit the root, that means that we're in an disconnected tree
3757
- // that has been unmounted.
3758
- return null;
3759
- }
3760
-
3761
- // This function is copied from React and should be kept in sync:
3762
- // https://github.com/facebook/react/blob/main/packages/react-reconciler/src/ReactFiberTreeReflection.js
3763
- // It would be nice if we updated React to inject this function directly (vs just indirectly via findDOMNode).
3764
- // BEGIN copied code
3765
- function findCurrentFiberUsingSlowPathByFiberInstance(
3766
- fiberInstance: FiberInstance,
3767
- ): Fiber | null {
3768
- const fiber = fiberInstance.data;
3769
- const alternate = fiber.alternate;
3770
- if (!alternate) {
3771
- // If there is no alternate, then we only need to check if it is mounted.
3772
- const nearestMounted = getNearestMountedFiber(fiber);
3773
-
3774
- if (nearestMounted === null) {
3775
- throw new Error('Unable to find node on an unmounted component.');
3776
- }
3777
-
3778
- if (nearestMounted !== fiber) {
3779
- return null;
3780
- }
3781
- return fiber;
3782
- }
3783
- // If we have two possible branches, we'll walk backwards up to the root
3784
- // to see what path the root points to. On the way we may hit one of the
3785
- // special cases and we'll deal with them.
3786
- let a: Fiber = fiber;
3787
- let b: Fiber = alternate;
3788
- while (true) {
3789
- const parentA = a.return;
3790
- if (parentA === null) {
3791
- // We're at the root.
3792
- break;
3793
- }
3794
- const parentB = parentA.alternate;
3795
- if (parentB === null) {
3796
- // There is no alternate. This is an unusual case. Currently, it only
3797
- // happens when a Suspense component is hidden. An extra fragment fiber
3798
- // is inserted in between the Suspense fiber and its children. Skip
3799
- // over this extra fragment fiber and proceed to the next parent.
3800
- const nextParent = parentA.return;
3801
- if (nextParent !== null) {
3802
- a = b = nextParent;
3803
- continue;
3804
- }
3805
- // If there's no parent, we're at the root.
3806
- break;
3807
- }
3808
-
3809
- // If both copies of the parent fiber point to the same child, we can
3810
- // assume that the child is current. This happens when we bailout on low
3811
- // priority: the bailed out fiber's child reuses the current child.
3812
- if (parentA.child === parentB.child) {
3813
- let child = parentA.child;
3814
- while (child) {
3815
- if (child === a) {
3816
- // We've determined that A is the current branch.
3817
- assertIsMounted(parentA);
3818
- return fiber;
3819
- }
3820
- if (child === b) {
3821
- // We've determined that B is the current branch.
3822
- assertIsMounted(parentA);
3823
- return alternate;
3824
- }
3825
- child = child.sibling;
3826
- }
3827
-
3828
- // We should never have an alternate for any mounting node. So the only
3829
- // way this could possibly happen is if this was unmounted, if at all.
3830
- throw new Error('Unable to find node on an unmounted component.');
3831
- }
3832
-
3833
- if (a.return !== b.return) {
3834
- // The return pointer of A and the return pointer of B point to different
3835
- // fibers. We assume that return pointers never criss-cross, so A must
3836
- // belong to the child set of A.return, and B must belong to the child
3837
- // set of B.return.
3838
- a = parentA;
3839
- b = parentB;
3840
- } else {
3841
- // The return pointers point to the same fiber. We'll have to use the
3842
- // default, slow path: scan the child sets of each parent alternate to see
3843
- // which child belongs to which set.
3844
- //
3845
- // Search parent A's child set
3846
- let didFindChild = false;
3847
- let child = parentA.child;
3848
- while (child) {
3849
- if (child === a) {
3850
- didFindChild = true;
3851
- a = parentA;
3852
- b = parentB;
3853
- break;
3854
- }
3855
- if (child === b) {
3856
- didFindChild = true;
3857
- b = parentA;
3858
- a = parentB;
3859
- break;
3860
- }
3861
- child = child.sibling;
3862
- }
3863
- if (!didFindChild) {
3864
- // Search parent B's child set
3865
- child = parentB.child;
3866
- while (child) {
3867
- if (child === a) {
3868
- didFindChild = true;
3869
- a = parentB;
3870
- b = parentA;
3871
- break;
3872
- }
3873
- if (child === b) {
3874
- didFindChild = true;
3875
- b = parentB;
3876
- a = parentA;
3877
- break;
3878
- }
3879
- child = child.sibling;
3880
- }
3881
-
3882
- if (!didFindChild) {
3883
- throw new Error(
3884
- 'Child was not found in either parent set. This indicates a bug ' +
3885
- 'in React related to the return pointer. Please file an issue.',
3886
- );
3887
- }
3888
- }
3889
- }
3890
-
3891
- if (a.alternate !== b) {
3892
- throw new Error(
3893
- "Return fibers should always be each others' alternates. " +
3894
- 'This error is likely caused by a bug in React. Please file an issue.',
3895
- );
3896
- }
3897
- }
3898
-
3899
- // If the root is not a host container, we're in a disconnected tree. I.e.
3900
- // unmounted.
3901
- if (a.tag !== HostRoot) {
3902
- throw new Error('Unable to find node on an unmounted component.');
3903
- }
3904
-
3905
- if (a.stateNode.current === a) {
3906
- // We've determined that A is the current branch.
3907
- return fiber;
3908
- }
3909
- // Otherwise B has to be current branch.
3910
- return alternate;
3911
- }
3912
-
3913
- // END copied code
3914
-
3712
function getElementAttributeByPath(
3713
id: number,
3714
path: Array<string | number>,
@@ -4096,8 +3893,7 @@ export function attach(
3893
return {instance, style};
3894
}
3895
4099
- const fiber =
4100
- findCurrentFiberUsingSlowPathByFiberInstance(devtoolsInstance);
3896
+ const fiber = devtoolsInstance.data;
3897
if (fiber !== null) {
3898
instance = fiber.stateNode;
3899
@@ -4153,7 +3949,7 @@ export function attach(
3949
function inspectFiberInstanceRaw(
3950
fiberInstance: FiberInstance,
3951
): InspectedElement | null {
4156
- const fiber = findCurrentFiberUsingSlowPathByFiberInstance(fiberInstance);
3952
+ const fiber = fiberInstance.data;
3953
if (fiber == null) {
3954
return null;
3955
}
@@ -4913,8 +4709,7 @@ export function attach(
4709
// TODO: Handle VirtualInstance.
4710
return;
4711
}
4916
- const fiber =
4917
- findCurrentFiberUsingSlowPathByFiberInstance(devtoolsInstance);
4712
+ const fiber = devtoolsInstance.data;
4713
if (fiber !== null) {
4714
const instance = fiber.stateNode;
4715
@@ -4979,8 +4774,7 @@ export function attach(
4774
// TODO: Handle VirtualInstance.
4775
return;
4776
}
4982
- const fiber =
4983
- findCurrentFiberUsingSlowPathByFiberInstance(devtoolsInstance);
4777
+ const fiber = devtoolsInstance.data;
4778
if (fiber !== null) {
4779
const instance = fiber.stateNode;
4780
@@ -5055,8 +4849,7 @@ export function attach(
4849
// TODO: Handle VirtualInstance.
4850
return;
4851
}
5058
- const fiber =
5059
- findCurrentFiberUsingSlowPathByFiberInstance(devtoolsInstance);
4852
+ const fiber = devtoolsInstance.data;
4853
if (fiber !== null) {
4854
const instance = fiber.stateNode;
4855