UNPKG

3.44 kBJavaScriptView Raw
1// Extracted from https://github.com/facebook/react/blob/7bdf93b17a35a5d8fcf0ceae0bf48ed5e6b16688/src/renderers/shared/fiber/ReactFiberTreeReflection.js#L104-L228
2function findCurrentFiberUsingSlowPath(fiber) {
3 const { alternate } = fiber;
4 if (!alternate) {
5 return fiber;
6 }
7 // If we have two possible branches, we'll walk backwards up to the root
8 // to see what path the root points to. On the way we may hit one of the
9 // special cases and we'll deal with them.
10 let a = fiber;
11 let b = alternate;
12 while (true) { // eslint-disable-line
13 const parentA = a.return;
14 const parentB = parentA ? parentA.alternate : null;
15 if (!parentA || !parentB) {
16 // We're at the root.
17 break;
18 }
19
20 // If both copies of the parent fiber point to the same child, we can
21 // assume that the child is current. This happens when we bailout on low
22 // priority: the bailed out fiber's child reuses the current child.
23 if (parentA.child === parentB.child) {
24 let { child } = parentA;
25 while (child) {
26 if (child === a) {
27 // We've determined that A is the current branch.
28 return fiber;
29 }
30 if (child === b) {
31 // We've determined that B is the current branch.
32 return alternate;
33 }
34 child = child.sibling;
35 }
36 // We should never have an alternate for any mounting node. So the only
37 // way this could possibly happen is if this was unmounted, if at all.
38 throw new Error('Unable to find node on an unmounted component.');
39 }
40
41 if (a.return !== b.return) {
42 // The return pointer of A and the return pointer of B point to different
43 // fibers. We assume that return pointers never criss-cross, so A must
44 // belong to the child set of A.return, and B must belong to the child
45 // set of B.return.
46 a = parentA;
47 b = parentB;
48 } else {
49 // The return pointers point to the same fiber. We'll have to use the
50 // default, slow path: scan the child sets of each parent alternate to see
51 // which child belongs to which set.
52 //
53 // Search parent A's child set
54 let didFindChild = false;
55 let { child } = parentA;
56 while (child) {
57 if (child === a) {
58 didFindChild = true;
59 a = parentA;
60 b = parentB;
61 break;
62 }
63 if (child === b) {
64 didFindChild = true;
65 b = parentA;
66 a = parentB;
67 break;
68 }
69 child = child.sibling;
70 }
71 if (!didFindChild) {
72 // Search parent B's child set
73 ({ child } = parentB);
74 while (child) {
75 if (child === a) {
76 didFindChild = true;
77 a = parentB;
78 b = parentA;
79 break;
80 }
81 if (child === b) {
82 didFindChild = true;
83 b = parentB;
84 a = parentA;
85 break;
86 }
87 child = child.sibling;
88 }
89 if (!didFindChild) {
90 throw new Error('Child was not found in either parent set. This indicates a bug '
91 + 'in React related to the return pointer. Please file an issue.');
92 }
93 }
94 }
95 }
96 if (a.stateNode.current === a) {
97 // We've determined that A is the current branch.
98 return fiber;
99 }
100 // Otherwise B has to be current branch.
101 return alternate;
102}
103
104module.exports = findCurrentFiberUsingSlowPath;