1 | // Extracted from https://github.com/facebook/react/blob/7bdf93b17a35a5d8fcf0ceae0bf48ed5e6b16688/src/renderers/shared/fiber/ReactFiberTreeReflection.js#L104-L228
|
2 | function 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 |
|
104 | module.exports = findCurrentFiberUsingSlowPath;
|