diff --git a/src/renderers/dom/client/ReactMount.js b/src/renderers/dom/client/ReactMount.js index 57af82b39e..88ed3a01a8 100644 --- a/src/renderers/dom/client/ReactMount.js +++ b/src/renderers/dom/client/ReactMount.js @@ -28,7 +28,6 @@ var ReactUpdateQueue = require('ReactUpdateQueue'); var ReactUpdates = require('ReactUpdates'); var emptyObject = require('emptyObject'); -var containsNode = require('containsNode'); var instantiateReactComponent = require('instantiateReactComponent'); var invariant = require('invariant'); var setInnerHTML = require('setInnerHTML'); @@ -36,7 +35,6 @@ var shouldUpdateReactComponent = require('shouldUpdateReactComponent'); var warning = require('warning'); var ATTR_NAME = DOMProperty.ID_ATTRIBUTE_NAME; -var nodeCache = {}; var ELEMENT_NODE_TYPE = 1; var DOC_NODE_TYPE = 9; @@ -54,9 +52,6 @@ if (__DEV__) { var rootElementsByReactRootID = {}; } -// Used to store breadth-first search state in findComponentRoot. -var findComponentRootReusableArray = []; - /** * Finds the index of the first character * that's not common between the two given strings. @@ -99,33 +94,6 @@ function getReactRootID(container) { return rootElement && internalGetID(rootElement); } -/** - * Accessing node[ATTR_NAME] or calling getAttribute(ATTR_NAME) on a form - * element can return its control whose name or ID equals ATTR_NAME. All - * DOM nodes support `getAttributeNode` but this can also get called on - * other objects so just return '' if we're given something other than a - * DOM node (such as window). - * - * @param {?DOMElement|DOMWindow|DOMDocument|DOMTextNode} node DOM node. - * @return {string} ID of the supplied `domNode`. - */ -function getID(node) { - var id = internalGetID(node); - if (id) { - var cached = nodeCache[id]; - // TODO: Fix this whole concept of "validity" -- the cache just shouldn't - // have nodes that have been unmounted. - invariant( - !cached || cached === node || !isValid(cached, id), - 'ReactMount: Two valid but unequal nodes with the same `%s`: %s', - ATTR_NAME, id - ); - nodeCache[id] = node; - } - - return id; -} - function internalGetID(node) { // If node is something like a window, document, or text node, none of // which support attributes or a .getAttribute method, gracefully return @@ -133,112 +101,6 @@ function internalGetID(node) { return node && node.getAttribute && node.getAttribute(ATTR_NAME) || ''; } -/** - * Sets the React-specific ID of the given node. - * - * @param {DOMElement} node The DOM node whose ID will be set. - * @param {string} id The value of the ID attribute. - */ -function setID(node, id) { - var oldID = internalGetID(node); - if (oldID !== id) { - delete nodeCache[oldID]; - } - node.setAttribute(ATTR_NAME, id); - nodeCache[id] = node; -} - -/** - * Finds the node with the supplied ID if present in the cache. - */ -function getNodeIfCached(id) { - var node = nodeCache[id]; - // TODO: Fix this whole concept of "validity" -- the cache just shouldn't have - // nodes that have been unmounted. - if (node && isValid(node, id)) { - return node; - } -} - -/** - * Finds the node with the supplied React-generated DOM ID. - * - * @param {string} id A React-generated DOM ID. - * @return {DOMElement} DOM node with the suppled `id`. - * @internal - */ -function getNode(id) { - var node = getNodeIfCached(id); - if (node) { - return node; - } else { - return nodeCache[id] = ReactMount.findReactNodeByID(id); - } -} - -/** - * A node is "valid" if it is contained by a currently mounted container. - * - * This means that the node does not have to be contained by a document in - * order to be considered valid. - * - * @param {?DOMElement} node The candidate DOM node. - * @param {string} id The expected ID of the node. - * @return {boolean} Whether the node is contained by a mounted container. - */ -function isValid(node, id) { - if (node) { - invariant( - internalGetID(node) === id, - 'ReactMount: Unexpected modification of `%s`', - ATTR_NAME - ); - - var container = ReactMount.findReactContainerForID(id); - if (container && containsNode(container, node)) { - return true; - } - } - - return false; -} - -/** - * Causes the cache to forget about one React-specific ID. - * - * @param {string} id The ID to forget. - */ -function purgeID(id) { - delete nodeCache[id]; -} - -var deepestNodeSoFar = null; -function findDeepestCachedAncestorImpl(ancestorID) { - var ancestor = getNodeIfCached(ancestorID); - if (ancestor) { - deepestNodeSoFar = ancestor; - } else { - // This node isn't populated in the cache, so presumably none of its - // descendants are. Break out of the loop. - return false; - } -} - -/** - * Return the deepest cached node whose ID is a prefix of `targetID`. - */ -function findDeepestCachedAncestor(targetID) { - deepestNodeSoFar = null; - ReactInstanceHandles.traverseAncestors( - targetID, - findDeepestCachedAncestorImpl - ); - - var foundNode = deepestNodeSoFar; - deepestNodeSoFar = null; - return foundNode; -} - /** * Mounts this component and inserts it into the DOM. * @@ -344,47 +206,6 @@ function hasNonRootReactChild(node) { ReactInstanceHandles.getReactRootIDFromNodeID(reactRootID) : false; } -/** - * Returns the first (deepest) ancestor of a node which is rendered by this copy - * of React. - */ -function findFirstReactDOMImpl(node) { - // This node might be from another React instance, so we make sure not to - // examine the node cache here - for (; node && node.parentNode !== node; node = node.parentNode) { - if (node.nodeType !== 1) { - // Not a DOMElement, therefore not a React component - continue; - } - var nodeID = internalGetID(node); - if (!nodeID) { - continue; - } - var reactRootID = ReactInstanceHandles.getReactRootIDFromNodeID(nodeID); - - // If containersByReactRootID contains the container we find by crawling up - // the tree, we know that this instance of React rendered the node. - // nb. isValid's strategy (with containsNode) does not work because render - // trees may be nested and we don't want a false positive in that case. - var current = node; - var lastID; - do { - lastID = internalGetID(current); - current = current.parentNode; - if (current == null) { - // The passed-in node has been detached from the container it was - // originally rendered into. - return null; - } - } while (lastID !== reactRootID); - - if (current === containersByReactRootID[reactRootID]) { - return node; - } - } - return null; -} - /** * Temporary (?) hack so that we can store all top-level pending updates on * composites instead of having to worry about different types of components @@ -794,162 +615,6 @@ var ReactMount = { return true; }, - /** - * Finds the container DOM element that contains React component to which the - * supplied DOM `id` belongs. - * - * @param {string} id The ID of an element rendered by a React component. - * @return {?DOMElement} DOM element that contains the `id`. - */ - findReactContainerForID: function(id) { - var reactRootID = ReactInstanceHandles.getReactRootIDFromNodeID(id); - var container = containersByReactRootID[reactRootID]; - - if (__DEV__) { - var rootElement = rootElementsByReactRootID[reactRootID]; - if (rootElement && rootElement.parentNode !== container) { - warning( - // Call internalGetID here because getID calls isValid which calls - // findReactContainerForID (this function). - internalGetID(rootElement) === reactRootID, - 'ReactMount: Root element ID differed from reactRootID.' - ); - var containerChild = container.firstChild; - if (containerChild && - reactRootID === internalGetID(containerChild)) { - // If the container has a new child with the same ID as the old - // root element, then rootElementsByReactRootID[reactRootID] is - // just stale and needs to be updated. The case that deserves a - // warning is when the container is empty. - rootElementsByReactRootID[reactRootID] = containerChild; - } else { - warning( - false, - 'ReactMount: Root element has been removed from its original ' + - 'container. New container: %s', - rootElement.parentNode - ); - } - } - } - - return container; - }, - - /** - * Finds an element rendered by React with the supplied ID. - * - * @param {string} id ID of a DOM node in the React component. - * @return {DOMElement} Root DOM node of the React component. - */ - findReactNodeByID: function(id) { - var reactRoot = ReactMount.findReactContainerForID(id); - return ReactMount.findComponentRoot(reactRoot, id); - }, - - /** - * Traverses up the ancestors of the supplied node to find a node that is a - * DOM representation of a React component rendered by this copy of React. - * - * @param {*} node - * @return {?DOMEventTarget} - * @internal - */ - getFirstReactDOM: function(node) { - return findFirstReactDOMImpl(node); - }, - - /** - * Finds a node with the supplied `targetID` inside of the supplied - * `ancestorNode`. Exploits the ID naming scheme to perform the search - * quickly. - * - * @param {DOMEventTarget} ancestorNode Search from this root. - * @pararm {string} targetID ID of the DOM representation of the component. - * @return {DOMEventTarget} DOM node with the supplied `targetID`. - * @internal - */ - findComponentRoot: function(ancestorNode, targetID) { - var firstChildren = findComponentRootReusableArray; - var childIndex = 0; - - var deepestAncestor = findDeepestCachedAncestor(targetID) || ancestorNode; - - if (__DEV__) { - // This will throw on the next line; give an early warning - warning( - deepestAncestor != null, - 'React can\'t find the root component node for data-reactid value ' + - '`%s`. If you\'re seeing this message, it probably means that ' + - 'you\'ve loaded two copies of React on the page. At this time, only ' + - 'a single copy of React can be loaded at a time.', - targetID - ); - } - - firstChildren[0] = deepestAncestor.firstChild; - firstChildren.length = 1; - - while (childIndex < firstChildren.length) { - var child = firstChildren[childIndex++]; - var targetChild; - - while (child) { - var childID = ReactMount.getID(child); - if (childID) { - // Even if we find the node we're looking for, we finish looping - // through its siblings to ensure they're cached so that we don't have - // to revisit this node again. Otherwise, we make n^2 calls to getID - // when visiting the many children of a single node in order. - - if (targetID === childID) { - targetChild = child; - } else if (ReactInstanceHandles.isAncestorIDOf(childID, targetID)) { - // 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); - } - - } else { - // If this child had no ID, then there's a chance that it was - // injected automatically by the browser, as when a `