Fix findDOMNode algorithm
Andrew Clark committed
Jan 30, 2017 at 18:41 UTC
97f6786cba9cf1917ccc28d839a415c6a4c92581
1 file changed
+55
-8
src/renderers/shared/fiber/ReactFiberTreeReflection.js
+55
-8
@@ -101,17 +101,16 @@ function findCurrentFiberUsingSlowPath(fiber : Fiber) : Fiber | null {
101
let b = alternate;
102
while (true) {
103
let parentA = a.return;
104
- let parentB = b.return;
104
+ let parentB = parentA ? parentA.alternate : null;
105
if (!parentA || !parentB) {
106
// We're at the root.
107
break;
108
}
109
+
110
+ // If both copies of the parent fiber point to the same child, we can
111
+ // assume that the child is current. This happens when we bailout on low
112
+ // priority: the bailed out fiber's child reuses the current child.
113
if (parentA.child === parentB.child) {
110
- // If both parents are the same, then that is the current parent. If
111
- // they're different but point to the same child, then it doesn't matter.
112
- // Regardless, whatever child they point to is the current child.
113
- // So we can now determine which child is current by scanning the child
114
- // list for either A or B.
114
let child = parentA.child;
115
while (child) {
116
if (child === a) {
@@ -133,8 +132,56 @@ function findCurrentFiberUsingSlowPath(fiber : Fiber) : Fiber | null {
132
'Unable to find node on an unmounted component.'
133
);
134
}
136
- a = parentA;
137
- b = parentB;
135
+
136
+ if (a.return !== b.return) {
137
+ // The return pointer of A and the return pointer of B point to different
138
+ // fibers. We assume that return pointers never criss-cross, so A must
139
+ // belong to the child set of A.return, and B must belong to the child
140
+ // set of B.return.
141
+ a = parentA;
142
+ b = parentB;
143
+ } else {
144
+ // The return pointers pointer to the same fiber. We'll have to use the
145
+ // default, slow path: scan the child sets of each parent alternate to see
146
+ // which child belongs to which set.
147
+ //
148
+ // Search parent A's child set
149
+ let didFindChild = false;
150
+ let child = parentA.child;
151
+ while (child) {
152
+ if (child === a) {
153
+ didFindChild = true;
154
+ a = parentA;
155
+ b = parentB;
156
+ break;
157
+ }
158
+ if (child === b) {
159
+ didFindChild = true;
160
+ b = parentA;
161
+ a = parentB;
162
+ break;
163
+ }
164
+ child = child.sibling;
165
+ }
166
+ if (!didFindChild) {
167
+ // Search parent B's child set
168
+ child = parentB.child;
169
+ while (child) {
170
+ if (child === a) {
171
+ a = parentB;
172
+ b = parentA;
173
+ break;
174
+ }
175
+ if (child === b) {
176
+ b = parentB;
177
+ a = parentA;
178
+ break;
179
+ }
180
+ child = child.sibling;
181
+ }
182
+ }
183
+ }
184
+
185
invariant(
186
a.alternate === b,
187
'Return fibers should always be each others\' alternates.'