diff --git a/src/core/ReactMount.js b/src/core/ReactMount.js index 5d636a0a95e..a3b0440a1cf 100644 --- a/src/core/ReactMount.js +++ b/src/core/ReactMount.js @@ -46,6 +46,9 @@ if (__DEV__) { var rootElementsByReactRootID = {}; } +// Used to store breadth-first search state in findComponentRoot. +var findComponentRootReusableArray = []; + /** * @param {DOMElement} container DOM element that may contain a React component. * @return {?string} A "reactRoot" ID, if a React component is rendered. @@ -538,30 +541,39 @@ var ReactMount = { * @internal */ findComponentRoot: function(ancestorNode, id) { - var firstChildren = [ancestorNode.firstChild]; + var firstChildren = findComponentRootReusableArray; var childIndex = 0; + firstChildren[0] = ancestorNode.firstChild; + firstChildren.length = 1; + while (childIndex < firstChildren.length) { var child = firstChildren[childIndex++]; while (child) { var childID = ReactMount.getID(child); if (childID) { if (id === childID) { + // Emptying firstChildren/findComponentRootReusableArray is + // not necessary for correctness, but it helps the GC reclaim + // any nodes that were left at the end of the search. + firstChildren.length = 0; + return child; - } else if (ReactInstanceHandles.isAncestorIDOf(childID, id)) { + } + + if (ReactInstanceHandles.isAncestorIDOf(childID, id)) { // If we find a child whose ID is an ancestor of the given ID, // then we can be sure that we only want to search the subtree // rooted at this child, so we can throw out the rest of the // search state. firstChildren.length = childIndex = 0; firstChildren.push(child.firstChild); + + // Ignore the rest of this child's siblings and immediately + // continue the outer loop with child.firstChild as child. break; - } else { - // TODO This should not be necessary if the ID hierarchy is - // correct, but is occasionally necessary if the DOM has been - // modified in unexpected ways. - firstChildren.push(child.firstChild); } + } else { // If this child had no ID, then there's a chance that it was // injected automatically by the browser, as when a `` @@ -570,10 +582,13 @@ var ReactMount = { // branch, but not before examining the other siblings. firstChildren.push(child.firstChild); } + child = child.nextSibling; } } + firstChildren.length = 0; + if (__DEV__) { console.error( 'Error while invoking `findComponentRoot` with the following ' +