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

findDOMNode: Remove return pointer mutation (#20272)

The last step of the `findDOMNode` algorithm is a search of the current tree. When descending into a child node, it mutates `child.return` so that it points to the current fiber pair, instead of a work-in-progress. This can cause bugs if `findDOMNode` is called at the wrong time, like in an interleaved event. For this reason (among others), you're not suppposed to use `findDOMNode` in Concurrent Mode. However, we still have some internal uses that we haven't migrated. To reduce the potential for bugs, I've removed the `.return` pointer assignment in favor of recursion.

Andrew Clark committed Nov 16, 2020 at 17:09 UTC bf7b7aeb1070f5184733ece11e67902d1ace85bd
1 file changed +37 -51
packages/react-reconciler/src/ReactFiberTreeReflection.js
+37 -51
@@ -265,71 +265,57 @@ export function findCurrentFiberUsingSlowPath(fiber: Fiber): Fiber | null {
265
266 export function findCurrentHostFiber(parent: Fiber): Fiber | null {
267 const currentParent = findCurrentFiberUsingSlowPath(parent);
268 - if (!currentParent) {
269 - return null;
270 - }
268 + return currentParent !== null
269 + ? findCurrentHostFiberImpl(currentParent)
270 + : null;
271 +}
272
273 +function findCurrentHostFiberImpl(node: Fiber) {
274 // Next we'll drill down this component to find the first HostComponent/Text.
273 - let node: Fiber = currentParent;
274 - while (true) {
275 - if (node.tag === HostComponent || node.tag === HostText) {
276 - return node;
277 - } else if (node.child) {
278 - node.child.return = node;
279 - node = node.child;
280 - continue;
281 - }
282 - if (node === currentParent) {
283 - return null;
284 - }
285 - while (!node.sibling) {
286 - if (!node.return || node.return === currentParent) {
287 - return null;
288 - }
289 - node = node.return;
275 + if (node.tag === HostComponent || node.tag === HostText) {
276 + return node;
277 + }
278 +
279 + let child = node.child;
280 + while (child !== null) {
281 + const match = findCurrentHostFiberImpl(child);
282 + if (match !== null) {
283 + return match;
284 }
291 - node.sibling.return = node.return;
292 - node = node.sibling;
285 + child = child.sibling;
286 }
294 - // Flow needs the return null here, but ESLint complains about it.
295 - // eslint-disable-next-line no-unreachable
287 +
288 return null;
289 }
290
291 export function findCurrentHostFiberWithNoPortals(parent: Fiber): Fiber | null {
292 const currentParent = findCurrentFiberUsingSlowPath(parent);
301 - if (!currentParent) {
302 - return null;
303 - }
293 + return currentParent !== null
294 + ? findCurrentHostFiberWithNoPortalsImpl(currentParent)
295 + : null;
296 +}
297
298 +function findCurrentHostFiberWithNoPortalsImpl(node: Fiber) {
299 // Next we'll drill down this component to find the first HostComponent/Text.
306 - let node: Fiber = currentParent;
307 - while (true) {
308 - if (
309 - node.tag === HostComponent ||
310 - node.tag === HostText ||
311 - (enableFundamentalAPI && node.tag === FundamentalComponent)
312 - ) {
313 - return node;
314 - } else if (node.child && node.tag !== HostPortal) {
315 - node.child.return = node;
316 - node = node.child;
317 - continue;
318 - }
319 - if (node === currentParent) {
320 - return null;
321 - }
322 - while (!node.sibling) {
323 - if (!node.return || node.return === currentParent) {
324 - return null;
300 + if (
301 + node.tag === HostComponent ||
302 + node.tag === HostText ||
303 + (enableFundamentalAPI && node.tag === FundamentalComponent)
304 + ) {
305 + return node;
306 + }
307 +
308 + let child = node.child;
309 + while (child !== null) {
310 + if (child.tag !== HostPortal) {
311 + const match = findCurrentHostFiberWithNoPortalsImpl(child);
312 + if (match !== null) {
313 + return match;
314 }
326 - node = node.return;
315 }
328 - node.sibling.return = node.return;
329 - node = node.sibling;
316 + child = child.sibling;
317 }
331 - // Flow needs the return null here, but ESLint complains about it.
332 - // eslint-disable-next-line no-unreachable
318 +
319 return null;
320 }
321