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,