@samitouri / QOS-React-2 / commits / 4ba0e95a96

Kill ReactMount.getNode/getID/purgeID with fire

Ben Alpert committed Oct 17, 2015 at 20:38 UTC 4ba0e95a96507abbcb2819be328fc3d1ed3cc80f
12 files changed +32 -549
src/renderers/dom/client/ReactMount.js
-351
@@ -28,7 +28,6 @@ var ReactUpdateQueue = require('ReactUpdateQueue');
28 var ReactUpdates = require('ReactUpdates');
29
30 var emptyObject = require('emptyObject');
31 -var containsNode = require('containsNode');
31 var instantiateReactComponent = require('instantiateReactComponent');
32 var invariant = require('invariant');
33 var setInnerHTML = require('setInnerHTML');
@@ -36,7 +35,6 @@ var shouldUpdateReactComponent = require('shouldUpdateReactComponent');
35 var warning = require('warning');
36
37 var ATTR_NAME = DOMProperty.ID_ATTRIBUTE_NAME;
39 -var nodeCache = {};
38
39 var ELEMENT_NODE_TYPE = 1;
40 var DOC_NODE_TYPE = 9;
@@ -54,9 +52,6 @@ if (__DEV__) {
52 var rootElementsByReactRootID = {};
53 }
54
57 -// Used to store breadth-first search state in findComponentRoot.
58 -var findComponentRootReusableArray = [];
59 -
55 /**
56 * Finds the index of the first character
57 * that's not common between the two given strings.
@@ -99,33 +94,6 @@ function getReactRootID(container) {
94 return rootElement && internalGetID(rootElement);
95 }
96
102 -/**
103 - * Accessing node[ATTR_NAME] or calling getAttribute(ATTR_NAME) on a form
104 - * element can return its control whose name or ID equals ATTR_NAME. All
105 - * DOM nodes support `getAttributeNode` but this can also get called on
106 - * other objects so just return '' if we're given something other than a
107 - * DOM node (such as window).
108 - *
109 - * @param {?DOMElement|DOMWindow|DOMDocument|DOMTextNode} node DOM node.
110 - * @return {string} ID of the supplied `domNode`.
111 - */
112 -function getID(node) {
113 - var id = internalGetID(node);
114 - if (id) {
115 - var cached = nodeCache[id];
116 - // TODO: Fix this whole concept of "validity" -- the cache just shouldn't
117 - // have nodes that have been unmounted.
118 - invariant(
119 - !cached || cached === node || !isValid(cached, id),
120 - 'ReactMount: Two valid but unequal nodes with the same `%s`: %s',
121 - ATTR_NAME, id
122 - );
123 - nodeCache[id] = node;
124 - }
125 -
126 - return id;
127 -}
128 -
97 function internalGetID(node) {
98 // If node is something like a window, document, or text node, none of
99 // which support attributes or a .getAttribute method, gracefully return
@@ -133,112 +101,6 @@ function internalGetID(node) {
101 return node && node.getAttribute && node.getAttribute(ATTR_NAME) || '';
102 }
103
136 -/**
137 - * Sets the React-specific ID of the given node.
138 - *
139 - * @param {DOMElement} node The DOM node whose ID will be set.
140 - * @param {string} id The value of the ID attribute.
141 - */
142 -function setID(node, id) {
143 - var oldID = internalGetID(node);
144 - if (oldID !== id) {
145 - delete nodeCache[oldID];
146 - }
147 - node.setAttribute(ATTR_NAME, id);
148 - nodeCache[id] = node;
149 -}
150 -
151 -/**
152 - * Finds the node with the supplied ID if present in the cache.
153 - */
154 -function getNodeIfCached(id) {
155 - var node = nodeCache[id];
156 - // TODO: Fix this whole concept of "validity" -- the cache just shouldn't have
157 - // nodes that have been unmounted.
158 - if (node && isValid(node, id)) {
159 - return node;
160 - }
161 -}
162 -
163 -/**
164 - * Finds the node with the supplied React-generated DOM ID.
165 - *
166 - * @param {string} id A React-generated DOM ID.
167 - * @return {DOMElement} DOM node with the suppled `id`.
168 - * @internal
169 - */
170 -function getNode(id) {
171 - var node = getNodeIfCached(id);
172 - if (node) {
173 - return node;
174 - } else {
175 - return nodeCache[id] = ReactMount.findReactNodeByID(id);
176 - }
177 -}
178 -
179 -/**
180 - * A node is "valid" if it is contained by a currently mounted container.
181 - *
182 - * This means that the node does not have to be contained by a document in
183 - * order to be considered valid.
184 - *
185 - * @param {?DOMElement} node The candidate DOM node.
186 - * @param {string} id The expected ID of the node.
187 - * @return {boolean} Whether the node is contained by a mounted container.
188 - */
189 -function isValid(node, id) {
190 - if (node) {
191 - invariant(
192 - internalGetID(node) === id,
193 - 'ReactMount: Unexpected modification of `%s`',
194 - ATTR_NAME
195 - );
196 -
197 - var container = ReactMount.findReactContainerForID(id);
198 - if (container && containsNode(container, node)) {
199 - return true;
200 - }
201 - }
202 -
203 - return false;
204 -}
205 -
206 -/**
207 - * Causes the cache to forget about one React-specific ID.
208 - *
209 - * @param {string} id The ID to forget.
210 - */
211 -function purgeID(id) {
212 - delete nodeCache[id];
213 -}
214 -
215 -var deepestNodeSoFar = null;
216 -function findDeepestCachedAncestorImpl(ancestorID) {
217 - var ancestor = getNodeIfCached(ancestorID);
218 - if (ancestor) {
219 - deepestNodeSoFar = ancestor;
220 - } else {
221 - // This node isn't populated in the cache, so presumably none of its
222 - // descendants are. Break out of the loop.
223 - return false;
224 - }
225 -}
226 -
227 -/**
228 - * Return the deepest cached node whose ID is a prefix of `targetID`.
229 - */
230 -function findDeepestCachedAncestor(targetID) {
231 - deepestNodeSoFar = null;
232 - ReactInstanceHandles.traverseAncestors(
233 - targetID,
234 - findDeepestCachedAncestorImpl
235 - );
236 -
237 - var foundNode = deepestNodeSoFar;
238 - deepestNodeSoFar = null;
239 - return foundNode;
240 -}
241 -
104 /**
105 * Mounts this component and inserts it into the DOM.
106 *
@@ -344,47 +206,6 @@ function hasNonRootReactChild(node) {
206 ReactInstanceHandles.getReactRootIDFromNodeID(reactRootID) : false;
207 }
208
347 -/**
348 - * Returns the first (deepest) ancestor of a node which is rendered by this copy
349 - * of React.
350 - */
351 -function findFirstReactDOMImpl(node) {
352 - // This node might be from another React instance, so we make sure not to
353 - // examine the node cache here
354 - for (; node && node.parentNode !== node; node = node.parentNode) {
355 - if (node.nodeType !== 1) {
356 - // Not a DOMElement, therefore not a React component
357 - continue;
358 - }
359 - var nodeID = internalGetID(node);
360 - if (!nodeID) {
361 - continue;
362 - }
363 - var reactRootID = ReactInstanceHandles.getReactRootIDFromNodeID(nodeID);
364 -
365 - // If containersByReactRootID contains the container we find by crawling up
366 - // the tree, we know that this instance of React rendered the node.
367 - // nb. isValid's strategy (with containsNode) does not work because render
368 - // trees may be nested and we don't want a false positive in that case.
369 - var current = node;
370 - var lastID;
371 - do {
372 - lastID = internalGetID(current);
373 - current = current.parentNode;
374 - if (current == null) {
375 - // The passed-in node has been detached from the container it was
376 - // originally rendered into.
377 - return null;
378 - }
379 - } while (lastID !== reactRootID);
380 -
381 - if (current === containersByReactRootID[reactRootID]) {
382 - return node;
383 - }
384 - }
385 - return null;
386 -}
387 -
209 /**
210 * Temporary (?) hack so that we can store all top-level pending updates on
211 * composites instead of having to worry about different types of components
@@ -794,162 +615,6 @@ var ReactMount = {
615 return true;
616 },
617
797 - /**
798 - * Finds the container DOM element that contains React component to which the
799 - * supplied DOM `id` belongs.
800 - *
801 - * @param {string} id The ID of an element rendered by a React component.
802 - * @return {?DOMElement} DOM element that contains the `id`.
803 - */
804 - findReactContainerForID: function(id) {
805 - var reactRootID = ReactInstanceHandles.getReactRootIDFromNodeID(id);
806 - var container = containersByReactRootID[reactRootID];
807 -
808 - if (__DEV__) {
809 - var rootElement = rootElementsByReactRootID[reactRootID];
810 - if (rootElement && rootElement.parentNode !== container) {
811 - warning(
812 - // Call internalGetID here because getID calls isValid which calls
813 - // findReactContainerForID (this function).
814 - internalGetID(rootElement) === reactRootID,
815 - 'ReactMount: Root element ID differed from reactRootID.'
816 - );
817 - var containerChild = container.firstChild;
818 - if (containerChild &&
819 - reactRootID === internalGetID(containerChild)) {
820 - // If the container has a new child with the same ID as the old
821 - // root element, then rootElementsByReactRootID[reactRootID] is
822 - // just stale and needs to be updated. The case that deserves a
823 - // warning is when the container is empty.
824 - rootElementsByReactRootID[reactRootID] = containerChild;
825 - } else {
826 - warning(
827 - false,
828 - 'ReactMount: Root element has been removed from its original ' +
829 - 'container. New container: %s',
830 - rootElement.parentNode
831 - );
832 - }
833 - }
834 - }
835 -
836 - return container;
837 - },
838 -
839 - /**
840 - * Finds an element rendered by React with the supplied ID.
841 - *
842 - * @param {string} id ID of a DOM node in the React component.
843 - * @return {DOMElement} Root DOM node of the React component.
844 - */
845 - findReactNodeByID: function(id) {
846 - var reactRoot = ReactMount.findReactContainerForID(id);
847 - return ReactMount.findComponentRoot(reactRoot, id);
848 - },
849 -
850 - /**
851 - * Traverses up the ancestors of the supplied node to find a node that is a
852 - * DOM representation of a React component rendered by this copy of React.
853 - *
854 - * @param {*} node
855 - * @return {?DOMEventTarget}
856 - * @internal
857 - */
858 - getFirstReactDOM: function(node) {
859 - return findFirstReactDOMImpl(node);
860 - },
861 -
862 - /**
863 - * Finds a node with the supplied `targetID` inside of the supplied
864 - * `ancestorNode`. Exploits the ID naming scheme to perform the search
865 - * quickly.
866 - *
867 - * @param {DOMEventTarget} ancestorNode Search from this root.
868 - * @pararm {string} targetID ID of the DOM representation of the component.
869 - * @return {DOMEventTarget} DOM node with the supplied `targetID`.
870 - * @internal
871 - */
872 - findComponentRoot: function(ancestorNode, targetID) {
873 - var firstChildren = findComponentRootReusableArray;
874 - var childIndex = 0;
875 -
876 - var deepestAncestor = findDeepestCachedAncestor(targetID) || ancestorNode;
877 -
878 - if (__DEV__) {
879 - // This will throw on the next line; give an early warning
880 - warning(
881 - deepestAncestor != null,
882 - 'React can\'t find the root component node for data-reactid value ' +
883 - '`%s`. If you\'re seeing this message, it probably means that ' +
884 - 'you\'ve loaded two copies of React on the page. At this time, only ' +
885 - 'a single copy of React can be loaded at a time.',
886 - targetID
887 - );
888 - }
889 -
890 - firstChildren[0] = deepestAncestor.firstChild;
891 - firstChildren.length = 1;
892 -
893 - while (childIndex < firstChildren.length) {
894 - var child = firstChildren[childIndex++];
895 - var targetChild;
896 -
897 - while (child) {
898 - var childID = ReactMount.getID(child);
899 - if (childID) {
900 - // Even if we find the node we're looking for, we finish looping
901 - // through its siblings to ensure they're cached so that we don't have
902 - // to revisit this node again. Otherwise, we make n^2 calls to getID
903 - // when visiting the many children of a single node in order.
904 -
905 - if (targetID === childID) {
906 - targetChild = child;
907 - } else if (ReactInstanceHandles.isAncestorIDOf(childID, targetID)) {
908 - // If we find a child whose ID is an ancestor of the given ID,
909 - // then we can be sure that we only want to search the subtree
910 - // rooted at this child, so we can throw out the rest of the
911 - // search state.
912 - firstChildren.length = childIndex = 0;
913 - firstChildren.push(child.firstChild);
914 - }
915 -
916 - } else {
917 - // If this child had no ID, then there's a chance that it was
918 - // injected automatically by the browser, as when a `<table>`
919 - // element sprouts an extra `<tbody>` child as a side effect of
920 - // `.innerHTML` parsing. Optimistically continue down this
921 - // branch, but not before examining the other siblings.
922 - firstChildren.push(child.firstChild);
923 - }
924 -
925 - child = child.nextSibling;
926 - }
927 -
928 - if (targetChild) {
929 - // Emptying firstChildren/findComponentRootReusableArray is
930 - // not necessary for correctness, but it helps the GC reclaim
931 - // any nodes that were left at the end of the search.
932 - firstChildren.length = 0;
933 -
934 - return targetChild;
935 - }
936 - }
937 -
938 - firstChildren.length = 0;
939 -
940 - invariant(
941 - false,
942 - 'findComponentRoot(..., %s): Unable to find element. This probably ' +
943 - 'means the DOM was unexpectedly mutated (e.g., by the browser), ' +
944 - 'usually due to forgetting a <tbody> when using tables, nesting tags ' +
945 - 'like <form>, <p>, or <a>, or using non-SVG elements in an <svg> ' +
946 - 'parent. ' +
947 - 'Try inspecting the child nodes of the element with React ID `%s`.',
948 - targetID,
949 - ReactMount.getID(ancestorNode)
950 - );
951 - },
952 -
618 _mountImageIntoNode: function(
619 markup,
620 container,
@@ -1056,22 +721,6 @@ var ReactMount = {
721 ReactDOMComponentTree.precacheNode(instance, container.firstChild);
722 }
723 },
1059 -
1060 - /**
1061 - * React ID utilities.
1062 - */
1063 -
1064 - getReactRootID: getReactRootID,
1065 -
1066 - getID: getID,
1067 -
1068 - setID: setID,
1069 -
1070 - getNode: getNode,
1071 -
1072 - isValid: isValid,
1073 -
1074 - purgeID: purgeID,
724 };
725
726 ReactPerf.measureMethods(ReactMount, 'ReactMount', {
src/renderers/dom/client/__tests__/ReactMount-test.js
-55
@@ -218,61 +218,6 @@ describe('ReactMount', function() {
218 );
219 });
220
221 - it('should not crash in node cache when unmounting', function() {
222 - var Component = React.createClass({
223 - render: function() {
224 - // Add refs to some nodes so that they get traversed and cached
225 - return (
226 - <div ref="a">
227 - <div ref="b">b</div>
228 - {this.props.showC && <div>c</div>}
229 - </div>
230 - );
231 - },
232 - });
233 -
234 - var container = document.createElement('container');
235 -
236 - ReactDOM.render(<div><Component showC={false} /></div>, container);
237 -
238 - // Right now, A and B are in the cache. When we add C, it won't get added to
239 - // the cache (assuming markup-string mode).
240 - ReactDOM.render(<div><Component showC={true} /></div>, container);
241 -
242 - // Remove A, B, and C. Unmounting C shouldn't cause B to get recached.
243 - ReactDOM.render(<div></div>, container);
244 -
245 - // Add them back -- this shouldn't cause a cached node collision.
246 - ReactDOM.render(<div><Component showC={true} /></div>, container);
247 -
248 - ReactDOM.unmountComponentAtNode(container);
249 - });
250 -
251 - it('should not crash in node cache when unmounting, case 2', function() {
252 - var A = React.createClass({
253 - render: function() {
254 - return <a key={this.props.innerKey}>{this.props.innerKey}</a>;
255 - },
256 - });
257 - var Component = React.createClass({
258 - render: function() {
259 - return (
260 - <b>
261 - <i>{this.props.step === 1 && <q />}</i>
262 - {this.props.step === 1 && <A innerKey={this.props.step} />}
263 - </b>
264 - );
265 - },
266 - });
267 -
268 - var container = document.createElement('container');
269 -
270 - ReactDOM.render(<Component step={1} />, container);
271 - ReactDOM.render(<Component step={2} />, container);
272 - ReactDOM.render(<Component step={1} />, container);
273 - ReactMount.getID(container.querySelector('a'));
274 - });
275 -
221 it('passes the correct callback context', function() {
222 var container = document.createElement('div');
223 var calls = 0;
src/renderers/dom/client/__tests__/ReactRenderDocument-test.js
+10 -12
@@ -17,8 +17,6 @@ jest
17 var React;
18 var ReactDOM;
19 var ReactDOMServer;
20 -var ReactInstanceMap;
21 -var ReactMount;
20
21 var getTestDocument;
22
@@ -46,14 +44,12 @@ describe('rendering React components at document', function() {
44 React = require('React');
45 ReactDOM = require('ReactDOM');
46 ReactDOMServer = require('ReactDOMServer');
49 - ReactInstanceMap = require('ReactInstanceMap');
50 - ReactMount = require('ReactMount');
47 getTestDocument = require('getTestDocument');
48
49 testDocument = getTestDocument();
50 });
51
56 - it('should be able to get root component id for document node', function() {
52 + it('should be able to adopt server markup', function() {
53 expect(testDocument).not.toBeUndefined();
54
55 var Root = React.createClass({
@@ -64,22 +60,24 @@ describe('rendering React components at document', function() {
60 <title>Hello World</title>
61 </head>
62 <body>
67 - Hello world
63 + {'Hello ' + this.props.hello}
64 </body>
65 </html>
66 );
67 },
68 });
69
74 - var markup = ReactDOMServer.renderToString(<Root />);
70 + var markup = ReactDOMServer.renderToString(<Root hello="world" />);
71 testDocument = getTestDocument(markup);
76 - var component = ReactDOM.render(<Root />, testDocument);
72 + var body = testDocument.body;
73 +
74 + ReactDOM.render(<Root hello="world" />, testDocument);
75 expect(testDocument.body.innerHTML).toBe('Hello world');
76
79 - // TODO: This is a bad test. I have no idea what this is testing.
80 - // Node IDs is an implementation detail and not part of the public API.
81 - var componentID = ReactMount.getReactRootID(testDocument);
82 - expect(componentID).toBe(ReactInstanceMap.get(component)._rootNodeID);
77 + ReactDOM.render(<Root hello="moon" />, testDocument);
78 + expect(testDocument.body.innerHTML).toBe('Hello moon');
79 +
80 + expect(body).toBe(testDocument.body);
81 });
82
83 it('should not be able to unmount component from document node', function() {
src/renderers/dom/client/wrappers/ReactDOMInput.js
+3 -10
@@ -14,7 +14,6 @@
14 var DOMPropertyOperations = require('DOMPropertyOperations');
15 var LinkedValueUtils = require('LinkedValueUtils');
16 var ReactDOMComponentTree = require('ReactDOMComponentTree');
17 -var ReactMount = require('ReactMount');
17 var ReactUpdates = require('ReactUpdates');
18
19 var assign = require('Object.assign');
@@ -189,19 +188,13 @@ function _handleChange(event) {
188 // This will throw if radio buttons rendered by different copies of React
189 // and the same name are rendered into the same form (same as #1939).
190 // That's probably okay; we don't support it just as we don't support
192 - // mixing React with non-React.
193 - var otherID = ReactMount.getID(otherNode);
191 + // mixing React radio buttons with non-React ones.
192 + var otherInstance = ReactDOMComponentTree.getInstanceFromNode(otherNode);
193 invariant(
195 - otherID,
194 + otherInstance,
195 'ReactDOMInput: Mixing React and non-React radio inputs with the ' +
196 'same `name` is not supported.'
197 );
199 - var otherInstance = instancesByReactID[otherID];
200 - invariant(
201 - otherInstance,
202 - 'ReactDOMInput: Unknown radio button ID %s.',
203 - otherID
204 - );
198 // If this is a controlled radio button group, forcing the input that
199 // was previously checked to update will cause it to be come re-checked
200 // as appropriate.
src/renderers/dom/shared/ReactComponentBrowserEnvironment.js
-2
@@ -13,7 +13,6 @@
13
14 var DOMChildrenOperations = require('DOMChildrenOperations');
15 var ReactDOMIDOperations = require('ReactDOMIDOperations');
16 -var ReactMount = require('ReactMount');
16 var ReactPerf = require('ReactPerf');
17
18 /**
@@ -37,7 +36,6 @@ var ReactComponentBrowserEnvironment = {
36 * @private
37 */
38 unmountIDFromEnvironment: function(rootNodeID) {
40 - ReactMount.purgeID(rootNodeID);
39 },
40
41 };
src/renderers/dom/shared/ReactDOMComponent.js
-3
@@ -33,7 +33,6 @@ var ReactDOMInput = require('ReactDOMInput');
33 var ReactDOMOption = require('ReactDOMOption');
34 var ReactDOMSelect = require('ReactDOMSelect');
35 var ReactDOMTextarea = require('ReactDOMTextarea');
36 -var ReactMount = require('ReactMount');
36 var ReactMultiChild = require('ReactMultiChild');
37 var ReactPerf = require('ReactPerf');
38 var ReactUpdateQueue = require('ReactUpdateQueue');
@@ -662,8 +661,6 @@ ReactDOMComponent.Mixin = {
661 ReactDOMComponentTree.precacheNode(this, el);
662 this._flags |= Flags.hasCachedChildNodes;
663 DOMPropertyOperations.setAttributeForID(el, this._rootNodeID);
665 - // Populate node cache
666 - ReactMount.getID(el);
664 this._updateDOMProperties(null, props, transaction);
665 var lazyTree = DOMLazyTree(el);
666 this._createInitialChildren(transaction, props, context, lazyTree);
src/renderers/dom/shared/ReactDOMTextComponent.js
+1 -4
@@ -18,7 +18,6 @@ var DOMPropertyOperations = require('DOMPropertyOperations');
18 var ReactComponentBrowserEnvironment =
19 require('ReactComponentBrowserEnvironment');
20 var ReactDOMComponentTree = require('ReactDOMComponentTree');
21 -var ReactMount = require('ReactMount');
21
22 var assign = require('Object.assign');
23 var escapeTextContentForBrowser = require('escapeTextContentForBrowser');
@@ -99,10 +98,8 @@ assign(ReactDOMTextComponent.prototype, {
98 if (transaction.useCreateElement) {
99 var ownerDocument = nativeContainerInfo._ownerDocument;
100 var el = ownerDocument.createElement('span');
102 - this._nativeNode = el;
101 + ReactDOMComponentTree.precacheNode(this, el);
102 DOMPropertyOperations.setAttributeForID(el, rootID);
104 - // Populate node cache
105 - ReactMount.getID(el);
103 var lazyTree = DOMLazyTree(el);
104 DOMLazyTree.queueText(lazyTree, this._stringText);
105 return lazyTree;
src/renderers/shared/reconciler/__tests__/ReactCompositeComponent-test.js
-15
@@ -16,7 +16,6 @@ var MorphingComponent;
16 var React;
17 var ReactDOM;
18 var ReactCurrentOwner;
19 -var ReactMount;
19 var ReactPropTypes;
20 var ReactServerRendering;
21 var ReactTestUtils;
@@ -34,7 +33,6 @@ describe('ReactCompositeComponent', function() {
33 ReactCurrentOwner = require('ReactCurrentOwner');
34 ReactPropTypes = require('ReactPropTypes');
35 ReactTestUtils = require('ReactTestUtils');
37 - ReactMount = require('ReactMount');
36 ReactServerRendering = require('ReactServerRendering');
37 ReactUpdates = require('ReactUpdates');
38
@@ -487,8 +485,6 @@ describe('ReactCompositeComponent', function() {
485 var container = document.createElement('div');
486 var innerUnmounted = false;
487
490 - spyOn(ReactMount, 'purgeID').andCallThrough();
491 -
488 var Component = React.createClass({
489 render: function() {
490 return (
@@ -501,11 +497,6 @@ describe('ReactCompositeComponent', function() {
497 });
498 var Inner = React.createClass({
499 componentWillUnmount: function() {
504 - // It's important that ReactMount.purgeID is called after any component
505 - // lifecycle methods, because a componentWillUnmount implementation is
506 - // likely to call ReactDOM.findDOMNode(this), which will repopulate the
507 - // node cache after it's been cleared, causing a memory leak.
508 - expect(ReactMount.purgeID.calls.length).toBe(0);
500 innerUnmounted = true;
501 },
502 render: function() {
@@ -516,12 +507,6 @@ describe('ReactCompositeComponent', function() {
507 ReactDOM.render(<Component />, container);
508 ReactDOM.unmountComponentAtNode(container);
509 expect(innerUnmounted).toBe(true);
519 -
520 - // The text and both <div /> elements and their wrappers each call
521 - // unmountIDFromEnvironment which calls purgeID, for a total of 3.
522 - // TODO: Test the effect of this. E.g. does the node cache get repopulated
523 - // after a getDOMNode call?
524 - expect(ReactMount.purgeID.calls.length).toBe(3);
510 });
511
512 it('should warn when shouldComponentUpdate() returns undefined', function() {
src/renderers/shared/reconciler/__tests__/ReactIdentity-test.js
+12 -8
@@ -13,9 +13,9 @@
13
14 var React;
15 var ReactDOM;
16 +var ReactDOMComponentTree;
17 var ReactFragment;
18 var ReactTestUtils;
18 -var ReactMount;
19
20 describe('ReactIdentity', function() {
21
@@ -23,14 +23,16 @@ describe('ReactIdentity', function() {
23 jest.resetModuleRegistry();
24 React = require('React');
25 ReactDOM = require('ReactDOM');
26 + ReactDOMComponentTree = require('ReactDOMComponentTree');
27 ReactFragment = require('ReactFragment');
28 ReactTestUtils = require('ReactTestUtils');
28 - ReactMount = require('ReactMount');
29 });
30
31 var idExp = /^\.[^.]+(.*)$/;
32 function checkID(child, expectedID) {
33 - var actual = idExp.exec(ReactMount.getID(child));
33 + // TODO: Node IDs are not public API; rewrite these tests.
34 + var rootID = ReactDOMComponentTree.getInstanceFromNode(child)._rootNodeID;
35 + var actual = idExp.exec(rootID);
36 var expected = idExp.exec(expectedID);
37 expect(actual).toBeTruthy();
38 expect(expected).toBeTruthy();
@@ -297,14 +299,16 @@ describe('ReactIdentity', function() {
299 var wrapped = <TestContainer first={instance0} second={instance1} />;
300
301 wrapped = ReactDOM.render(wrapped, document.createElement('div'));
302 + var div = ReactDOM.findDOMNode(wrapped);
303
301 - var beforeID = ReactMount.getID(ReactDOM.findDOMNode(wrapped).firstChild);
302 -
304 + var beforeA = div.childNodes[0];
305 + var beforeB = div.childNodes[1];
306 wrapped.swap();
307 + var afterA = div.childNodes[1];
308 + var afterB = div.childNodes[0];
309
305 - var afterID = ReactMount.getID(ReactDOM.findDOMNode(wrapped).firstChild);
306 -
307 - expect(beforeID).not.toEqual(afterID);
310 + expect(beforeA).toBe(afterA);
311 + expect(beforeB).toBe(afterB);
312
313 });
314
src/renderers/shared/reconciler/__tests__/ReactInstanceHandles-test.js
-84
@@ -13,7 +13,6 @@
13
14 var React = require('React');
15 var ReactTestUtils = require('ReactTestUtils');
16 -var ReactMount = require('ReactMount');
16
17 /**
18 * Ensure that all callbacks are invoked, passing this unique argument.
@@ -74,89 +73,6 @@ describe('ReactInstanceHandles', function() {
73 aggregatedArgs = [];
74 });
75
77 - describe('findComponentRoot', function() {
78 - it('should find the correct node with prefix sibling IDs', function() {
79 - var parentNode = ReactTestUtils.renderIntoDocument(
80 - <div>
81 - <div />
82 - {[<div key="x" />]}
83 - </div>
84 - );
85 - var childNodeB = parentNode.childNodes[1];
86 -
87 - expect(
88 - ReactMount.getNode(
89 - getNodeID(childNodeB)
90 - )
91 - ).toBe(childNodeB);
92 - });
93 -
94 - it('should work around unidentified nodes', function() {
95 - var parentNode = ReactTestUtils.renderIntoDocument(
96 - <div>
97 - {[<div key="x" />]}
98 - </div>
99 - );
100 - var childNodeB = parentNode.childNodes[0];
101 -
102 - // No ID on `childNodeA`.
103 - var childNodeA = document.createElement('div');
104 - parentNode.insertBefore(childNodeA, childNodeB);
105 -
106 - expect(
107 - ReactMount.getNode(
108 - getNodeID(childNodeB)
109 - )
110 - ).toBe(childNodeB);
111 - });
112 -
113 - it('should throw if a rendered element cannot be found', function() {
114 - spyOn(console, 'error');
115 - var parentNode = ReactTestUtils.renderIntoDocument(
116 - <table>
117 - <tr />
118 - </table>
119 - );
120 - var childNodeA = parentNode.childNodes[0];
121 - var childNodeB;
122 - if (childNodeA.tagName === 'TR') {
123 - childNodeB = childNodeA;
124 - // No ID on `childNodeA`, it was "rendered by the browser".
125 - childNodeA = document.createElement('tbody');
126 - childNodeA.appendChild(childNodeB);
127 - parentNode.appendChild(childNodeA);
128 - } else {
129 - childNodeB = childNodeA.childNodes[0];
130 - }
131 - expect(childNodeA.tagName).toBe('TBODY');
132 -
133 - expect(
134 - ReactMount.getNode(
135 - getNodeID(childNodeB)
136 - )
137 - ).toBe(childNodeB);
138 -
139 - var junkID = getNodeID(childNodeB) + ':junk';
140 - expect(function() {
141 - ReactMount.getNode(
142 - junkID
143 - );
144 - }).toThrow(
145 - 'findComponentRoot(..., ' + junkID + '): Unable to find element. ' +
146 - 'This probably means the DOM was unexpectedly mutated (e.g., by the ' +
147 - 'browser), usually due to forgetting a <tbody> when using tables, ' +
148 - 'nesting tags like <form>, <p>, or <a>, or using non-SVG elements in ' +
149 - 'an <svg> parent. Try inspecting the child nodes of the element with ' +
150 - 'React ID ``.'
151 - );
152 -
153 - expect(console.error.argsForCall.length).toBe(1);
154 - expect(console.error.argsForCall[0][0]).toContain(
155 - '<tr> cannot appear as a child of <table>'
156 - );
157 - });
158 - });
159 -
76 describe('getReactRootIDFromNodeID', function() {
77 it('should support strings', function() {
78 var test = '.s_0_1.0..1';
src/renderers/shared/reconciler/__tests__/ReactMultiChildReconcile-test.js
+3 -2
@@ -13,8 +13,8 @@
13
14 var React = require('React');
15 var ReactDOM = require('ReactDOM');
16 +var ReactDOMComponentTree = require('ReactDOMComponentTree');
17 var ReactInstanceMap = require('ReactInstanceMap');
17 -var ReactMount = require('ReactMount');
18
19 var mapObject = require('mapObject');
20
@@ -190,7 +190,8 @@ function verifyDomOrderingAccurate(parentInstance, statusDisplays) {
190 var i;
191 var orderedDomIDs = [];
192 for (i = 0; i < statusDisplayNodes.length; i++) {
193 - orderedDomIDs.push(ReactMount.getID(statusDisplayNodes[i]));
193 + var inst = ReactDOMComponentTree.getInstanceFromNode(statusDisplayNodes[i]);
194 + orderedDomIDs.push(inst._rootNodeID);
195 }
196
197 var orderedLogicalIDs = [];
src/test/ReactDefaultPerf.js
+3 -3
@@ -13,6 +13,7 @@
13 'use strict';
14
15 var DOMProperty = require('DOMProperty');
16 +var ReactDOMComponentTree = require('ReactDOMComponentTree');
17 var ReactDefaultPerfAnalysis = require('ReactDefaultPerfAnalysis');
18 var ReactMount = require('ReactMount');
19 var ReactPerf = require('ReactPerf');
@@ -175,8 +176,7 @@ var ReactDefaultPerf = {
176 totalTime = performanceNow() - start;
177
178 if (fnName === '_mountImageIntoNode') {
178 - var mountID = ReactMount.getID(args[1]);
179 - ReactDefaultPerf._recordWrite(mountID, fnName, totalTime, args[0]);
179 + ReactDefaultPerf._recordWrite('', fnName, totalTime, args[0]);
180 } else if (fnName === 'dangerouslyProcessChildrenUpdates') {
181 // special format
182 args[0].forEach(function(update) {
@@ -206,7 +206,7 @@ var ReactDefaultPerf = {
206 if (moduleName === 'EventPluginHub') {
207 id = id._rootNodeID;
208 } else if (typeof id === 'object') {
209 - id = ReactMount.getID(args[0]);
209 + id = ReactDOMComponentTree.getInstanceFromNode(args[0])._rootNodeID;
210 }
211 ReactDefaultPerf._recordWrite(
212 id,