react 0.8.0 → 0.9.0-rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/README.md +0 -8
  2. package/addons.js +0 -3
  3. package/lib/AutoFocusMixin.js +30 -0
  4. package/lib/CSSCore.js +22 -21
  5. package/lib/CSSProperty.js +31 -0
  6. package/lib/ChangeEventPlugin.js +26 -4
  7. package/lib/ClientReactRootIndex.js +30 -0
  8. package/lib/CompositionEventPlugin.js +57 -9
  9. package/lib/DOMChildrenOperations.js +32 -2
  10. package/lib/DOMProperty.js +2 -0
  11. package/lib/DOMPropertyOperations.js +14 -1
  12. package/lib/Danger.js +8 -7
  13. package/lib/DefaultDOMPropertyConfig.js +12 -2
  14. package/lib/EnterLeaveEventPlugin.js +37 -4
  15. package/lib/EventConstants.js +3 -0
  16. package/lib/EventListener.js +42 -34
  17. package/lib/EventPluginHub.js +113 -12
  18. package/lib/EventPluginRegistry.js +39 -16
  19. package/lib/EventPluginUtils.js +32 -3
  20. package/lib/EventPropagators.js +6 -42
  21. package/lib/ExecutionEnvironment.js +3 -0
  22. package/lib/LinkedValueUtils.js +161 -0
  23. package/lib/PooledClass.js +6 -0
  24. package/lib/React.js +27 -3
  25. package/lib/ReactCSSTransitionGroup.js +65 -0
  26. package/lib/{ReactTransitionableChild.js → ReactCSSTransitionGroupChild.js} +21 -35
  27. package/lib/ReactComponent.js +87 -52
  28. package/lib/ReactComponentBrowserEnvironment.js +67 -49
  29. package/lib/ReactComponentEnvironment.js +2 -0
  30. package/lib/ReactCompositeComponent.js +547 -112
  31. package/lib/ReactContext.js +67 -0
  32. package/lib/ReactDOM.js +13 -0
  33. package/lib/ReactDOMButton.js +4 -0
  34. package/lib/ReactDOMComponent.js +46 -21
  35. package/lib/ReactDOMForm.js +9 -2
  36. package/lib/ReactDOMIDOperations.js +105 -60
  37. package/lib/ReactDOMImg.js +58 -0
  38. package/lib/ReactDOMInput.js +26 -14
  39. package/lib/ReactDOMOption.js +1 -0
  40. package/lib/ReactDOMSelect.js +36 -17
  41. package/lib/ReactDOMTextarea.js +12 -8
  42. package/lib/ReactDefaultInjection.js +50 -26
  43. package/lib/ReactDefaultPerf.js +207 -370
  44. package/lib/ReactDefaultPerfAnalysis.js +199 -0
  45. package/lib/ReactErrorUtils.js +5 -14
  46. package/lib/ReactEventEmitter.js +141 -145
  47. package/lib/ReactEventEmitterMixin.js +0 -32
  48. package/lib/ReactEventTopLevelCallback.js +32 -12
  49. package/lib/ReactInjection.js +39 -0
  50. package/lib/ReactInstanceHandles.js +35 -19
  51. package/lib/ReactLink.js +1 -1
  52. package/lib/ReactMount.js +127 -103
  53. package/lib/ReactMountReady.js +1 -1
  54. package/lib/ReactMultiChild.js +30 -46
  55. package/lib/ReactMultiChildUpdateTypes.js +2 -0
  56. package/lib/ReactOwner.js +10 -2
  57. package/lib/ReactPerf.js +5 -8
  58. package/lib/ReactPropTransferer.js +40 -21
  59. package/lib/ReactPropTypeLocationNames.js +31 -0
  60. package/lib/ReactPropTypeLocations.js +29 -0
  61. package/lib/ReactPropTypes.js +248 -47
  62. package/lib/ReactPutListenerQueue.js +61 -0
  63. package/lib/ReactReconcileTransaction.js +20 -0
  64. package/lib/ReactRootIndex.js +36 -0
  65. package/lib/ReactServerRendering.js +8 -11
  66. package/lib/ReactTextComponent.js +8 -3
  67. package/lib/{ReactTransitionKeySet.js → ReactTransitionChildMapping.js} +42 -47
  68. package/lib/ReactTransitionGroup.js +132 -57
  69. package/lib/ReactUpdates.js +14 -11
  70. package/lib/ReactWithAddons.js +7 -2
  71. package/lib/SelectEventPlugin.js +22 -39
  72. package/lib/ServerReactRootIndex.js +36 -0
  73. package/lib/SimpleEventPlugin.js +54 -6
  74. package/lib/SyntheticClipboardEvent.js +7 -1
  75. package/lib/SyntheticDragEvent.js +44 -0
  76. package/lib/SyntheticEvent.js +2 -1
  77. package/lib/SyntheticKeyboardEvent.js +4 -2
  78. package/lib/SyntheticWheelEvent.js +10 -7
  79. package/lib/Transaction.js +61 -36
  80. package/lib/cloneWithProps.js +59 -0
  81. package/lib/createArrayFrom.js +10 -13
  82. package/lib/createFullPageComponent.js +63 -0
  83. package/lib/cx.js +2 -2
  84. package/lib/flattenChildren.js +5 -2
  85. package/lib/getActiveElement.js +4 -3
  86. package/lib/getEventKey.js +85 -0
  87. package/lib/getMarkupWrap.js +10 -0
  88. package/lib/getTextContentAccessor.js +5 -3
  89. package/lib/getUnboundedScrollPosition.js +2 -2
  90. package/lib/invariant.js +12 -4
  91. package/lib/isEventSupported.js +7 -11
  92. package/lib/mergeHelpers.js +5 -6
  93. package/lib/onlyChild.js +43 -0
  94. package/lib/shouldUpdateReactComponent.js +58 -0
  95. package/lib/toArray.js +75 -0
  96. package/lib/traverseAllChildren.js +69 -7
  97. package/lib/warning.js +40 -0
  98. package/package.json +2 -3
  99. package/react.js +0 -3
  100. package/ReactJSErrors.js +0 -40
  101. package/lib/$.js +0 -46
  102. package/lib/CallbackRegistry.js +0 -91
  103. package/lib/LinkedValueMixin.js +0 -68
  104. package/lib/ex.js +0 -49
  105. package/lib/filterAttributes.js +0 -45
  106. package/lib/ge.js +0 -76
  107. package/lib/mutateHTMLNodeWithMarkup.js +0 -100
@@ -27,38 +27,6 @@ function runEventQueueInBatch(events) {
27
27
  }
28
28
 
29
29
  var ReactEventEmitterMixin = {
30
- /**
31
- * Whether or not `ensureListening` has been invoked.
32
- * @type {boolean}
33
- * @private
34
- */
35
- _isListening: false,
36
-
37
- /**
38
- * Function, must be implemented. Listens to events on the top level of the
39
- * application.
40
- *
41
- * @abstract
42
- *
43
- * listenAtTopLevel: null,
44
- */
45
-
46
- /**
47
- * Ensures that top-level event delegation listeners are installed.
48
- *
49
- * There are issues with listening to both touch events and mouse events on
50
- * the top-level, so we make the caller choose which one to listen to. (If
51
- * there's a touch top-level listeners, anchors don't receive clicks for some
52
- * reason, and only in some cases).
53
- *
54
- * @param {*} config Configuration passed through to `listenAtTopLevel`.
55
- */
56
- ensureListening: function(config) {
57
- if (!config.contentDocument._reactIsListening) {
58
- this.listenAtTopLevel(config.touchNotMouse, config.contentDocument);
59
- config.contentDocument._reactIsListening = true;
60
- }
61
- },
62
30
 
63
31
  /**
64
32
  * Streams a fired top-level event to `EventPluginHub` where plugins have the
@@ -20,6 +20,7 @@
20
20
  "use strict";
21
21
 
22
22
  var ReactEventEmitter = require("./ReactEventEmitter");
23
+ var ReactInstanceHandles = require("./ReactInstanceHandles");
23
24
  var ReactMount = require("./ReactMount");
24
25
 
25
26
  var getEventTarget = require("./getEventTarget");
@@ -30,6 +31,24 @@ var getEventTarget = require("./getEventTarget");
30
31
  */
31
32
  var _topLevelListenersEnabled = true;
32
33
 
34
+ /**
35
+ * Finds the parent React component of `node`.
36
+ *
37
+ * @param {*} node
38
+ * @return {?DOMEventTarget} Parent container, or `null` if the specified node
39
+ * is not nested.
40
+ */
41
+ function findParent(node) {
42
+ // TODO: It may be a good idea to cache this to prevent unnecessary DOM
43
+ // traversal, but caching is difficult to do correctly without using a
44
+ // mutation observer to listen for all DOM changes.
45
+ var nodeID = ReactMount.getID(node);
46
+ var rootID = ReactInstanceHandles.getReactRootIDFromNodeID(nodeID);
47
+ var container = ReactMount.findReactContainerForID(rootID);
48
+ var parent = ReactMount.getFirstReactDOM(container);
49
+ return parent;
50
+ }
51
+
33
52
  /**
34
53
  * Top-level callback creator used to implement event handling using delegation.
35
54
  * This is used via dependency injection.
@@ -66,21 +85,22 @@ var ReactEventTopLevelCallback = {
66
85
  if (!_topLevelListenersEnabled) {
67
86
  return;
68
87
  }
69
- // TODO: Remove when synthetic events are ready, this is for IE<9.
70
- if (nativeEvent.srcElement &&
71
- nativeEvent.srcElement !== nativeEvent.target) {
72
- nativeEvent.target = nativeEvent.srcElement;
73
- }
74
88
  var topLevelTarget = ReactMount.getFirstReactDOM(
75
89
  getEventTarget(nativeEvent)
76
90
  ) || window;
77
- var topLevelTargetID = ReactMount.getID(topLevelTarget) || '';
78
- ReactEventEmitter.handleTopLevel(
79
- topLevelType,
80
- topLevelTarget,
81
- topLevelTargetID,
82
- nativeEvent
83
- );
91
+
92
+ // Loop through the hierarchy, in case there's any nested components.
93
+ while (topLevelTarget) {
94
+ var topLevelTargetID = ReactMount.getID(topLevelTarget) || '';
95
+ ReactEventEmitter.handleTopLevel(
96
+ topLevelType,
97
+ topLevelTarget,
98
+ topLevelTargetID,
99
+ nativeEvent
100
+ );
101
+
102
+ topLevelTarget = findParent(topLevelTarget);
103
+ }
84
104
  };
85
105
  }
86
106
 
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Copyright 2013 Facebook, Inc.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ *
16
+ * @providesModule ReactInjection
17
+ */
18
+
19
+ "use strict";
20
+
21
+ var DOMProperty = require("./DOMProperty");
22
+ var EventPluginHub = require("./EventPluginHub");
23
+ var ReactDOM = require("./ReactDOM");
24
+ var ReactEventEmitter = require("./ReactEventEmitter");
25
+ var ReactPerf = require("./ReactPerf");
26
+ var ReactRootIndex = require("./ReactRootIndex");
27
+ var ReactUpdates = require("./ReactUpdates");
28
+
29
+ var ReactInjection = {
30
+ DOMProperty: DOMProperty.injection,
31
+ EventPluginHub: EventPluginHub.injection,
32
+ DOM: ReactDOM.injection,
33
+ EventEmitter: ReactEventEmitter.injection,
34
+ Perf: ReactPerf.injection,
35
+ RootIndex: ReactRootIndex.injection,
36
+ Updates: ReactUpdates.injection
37
+ };
38
+
39
+ module.exports = ReactInjection;
@@ -19,6 +19,8 @@
19
19
 
20
20
  "use strict";
21
21
 
22
+ var ReactRootIndex = require("./ReactRootIndex");
23
+
22
24
  var invariant = require("./invariant");
23
25
 
24
26
  var SEPARATOR = '.';
@@ -29,15 +31,6 @@ var SEPARATOR_LENGTH = SEPARATOR.length;
29
31
  */
30
32
  var MAX_TREE_DEPTH = 100;
31
33
 
32
- /**
33
- * Size of the reactRoot ID space. We generate random numbers for React root
34
- * IDs and if there's a collision the events and DOM update system will
35
- * get confused. If we assume 100 React components per page, and a user
36
- * loads 1 page per minute 24/7 for 50 years, with a mount point space of
37
- * 9,999,999 the likelihood of never having a collision is 99.997%.
38
- */
39
- var GLOBAL_MOUNT_POINT_MAX = 9999999;
40
-
41
34
  /**
42
35
  * Creates a DOM ID prefix to use when mounting React components.
43
36
  *
@@ -46,7 +39,7 @@ var GLOBAL_MOUNT_POINT_MAX = 9999999;
46
39
  * @internal
47
40
  */
48
41
  function getReactRootIDString(index) {
49
- return SEPARATOR + 'r[' + index.toString(36) + ']';
42
+ return SEPARATOR + index.toString(36);
50
43
  }
51
44
 
52
45
  /**
@@ -175,7 +168,8 @@ function getFirstCommonAncestorID(oneID, twoID) {
175
168
 
176
169
  /**
177
170
  * Traverses the parent path between two IDs (either up or down). The IDs must
178
- * not be the same, and there must exist a parent path between them.
171
+ * not be the same, and there must exist a parent path between them. If the
172
+ * callback returns `false`, traversal is stopped.
179
173
  *
180
174
  * @param {?string} start ID at which to start traversal.
181
175
  * @param {?string} stop ID at which to end traversal.
@@ -204,10 +198,11 @@ function traverseParentPath(start, stop, cb, arg, skipFirst, skipLast) {
204
198
  var depth = 0;
205
199
  var traverse = traverseUp ? getParentID : getNextDescendantID;
206
200
  for (var id = start; /* until break */; id = traverse(id, stop)) {
201
+ var ret;
207
202
  if ((!skipFirst || id !== start) && (!skipLast || id !== stop)) {
208
- cb(id, traverseUp, arg);
203
+ ret = cb(id, traverseUp, arg);
209
204
  }
210
- if (id === stop) {
205
+ if (ret === false || id === stop) {
211
206
  // Only break //after// visiting `stop`.
212
207
  break;
213
208
  }
@@ -229,10 +224,12 @@ function traverseParentPath(start, stop, cb, arg, skipFirst, skipLast) {
229
224
  */
230
225
  var ReactInstanceHandles = {
231
226
 
227
+ /**
228
+ * Constructs a React root ID
229
+ * @return {string} A React root ID.
230
+ */
232
231
  createReactRootID: function() {
233
- return getReactRootIDString(
234
- Math.ceil(Math.random() * GLOBAL_MOUNT_POINT_MAX)
235
- );
232
+ return getReactRootIDString(ReactRootIndex.createReactRootIndex());
236
233
  },
237
234
 
238
235
  /**
@@ -244,7 +241,7 @@ var ReactInstanceHandles = {
244
241
  * @internal
245
242
  */
246
243
  createReactID: function(rootID, name) {
247
- return rootID + SEPARATOR + name;
244
+ return rootID + name;
248
245
  },
249
246
 
250
247
  /**
@@ -256,8 +253,11 @@ var ReactInstanceHandles = {
256
253
  * @internal
257
254
  */
258
255
  getReactRootIDFromNodeID: function(id) {
259
- var regexResult = /\.r\[[^\]]+\]/.exec(id);
260
- return regexResult && regexResult[0];
256
+ if (id && id.charAt(0) === SEPARATOR && id.length > 1) {
257
+ var index = id.indexOf(SEPARATOR, 1);
258
+ return index > -1 ? id.substr(0, index) : id;
259
+ }
260
+ return null;
261
261
  },
262
262
 
263
263
  /**
@@ -301,6 +301,22 @@ var ReactInstanceHandles = {
301
301
  }
302
302
  },
303
303
 
304
+ /**
305
+ * Traverse a node ID, calling the supplied `cb` for each ancestor ID. For
306
+ * example, passing `.0.$row-0.1` would result in `cb` getting called
307
+ * with `.0`, `.0.$row-0`, and `.0.$row-0.1`.
308
+ *
309
+ * NOTE: This traversal happens on IDs without touching the DOM.
310
+ *
311
+ * @param {string} targetID ID of the target node.
312
+ * @param {function} cb Callback to invoke.
313
+ * @param {*} arg Argument to invoke the callback with.
314
+ * @internal
315
+ */
316
+ traverseAncestors: function(targetID, cb, arg) {
317
+ traverseParentPath('', targetID, cb, arg, true, false);
318
+ },
319
+
304
320
  /**
305
321
  * Exposed for unit testing.
306
322
  * @private
package/lib/ReactLink.js CHANGED
@@ -39,7 +39,7 @@
39
39
  * });
40
40
  *
41
41
  * We have provided some sugary mixins to make the creation and
42
- * consumption of ReactLink easier; see LinkedValueMixin and LinkedStateMixin.
42
+ * consumption of ReactLink easier; see LinkedValueUtils and LinkedStateMixin.
43
43
  */
44
44
 
45
45
  /**
package/lib/ReactMount.js CHANGED
@@ -18,17 +18,19 @@
18
18
 
19
19
  "use strict";
20
20
 
21
+ var DOMProperty = require("./DOMProperty");
21
22
  var ReactEventEmitter = require("./ReactEventEmitter");
22
23
  var ReactInstanceHandles = require("./ReactInstanceHandles");
24
+ var ReactPerf = require("./ReactPerf");
23
25
 
24
- var $ = require("./$");
25
26
  var containsNode = require("./containsNode");
26
27
  var getReactRootElementInContainer = require("./getReactRootElementInContainer");
27
28
  var invariant = require("./invariant");
29
+ var shouldUpdateReactComponent = require("./shouldUpdateReactComponent");
28
30
 
29
31
  var SEPARATOR = ReactInstanceHandles.SEPARATOR;
30
32
 
31
- var ATTR_NAME = 'data-reactid';
33
+ var ATTR_NAME = DOMProperty.ID_ATTRIBUTE_NAME;
32
34
  var nodeCache = {};
33
35
 
34
36
  var ELEMENT_NODE_TYPE = 1;
@@ -45,6 +47,9 @@ if ("production" !== process.env.NODE_ENV) {
45
47
  var rootElementsByReactRootID = {};
46
48
  }
47
49
 
50
+ // Used to store breadth-first search state in findComponentRoot.
51
+ var findComponentRootReusableArray = [];
52
+
48
53
  /**
49
54
  * @param {DOMElement} container DOM element that may contain a React component.
50
55
  * @return {?string} A "reactRoot" ID, if a React component is rendered.
@@ -158,15 +163,45 @@ function purgeID(id) {
158
163
  delete nodeCache[id];
159
164
  }
160
165
 
166
+ var deepestNodeSoFar = null;
167
+ function findDeepestCachedAncestorImpl(ancestorID) {
168
+ var ancestor = nodeCache[ancestorID];
169
+ if (ancestor && isValid(ancestor, ancestorID)) {
170
+ deepestNodeSoFar = ancestor;
171
+ } else {
172
+ // This node isn't populated in the cache, so presumably none of its
173
+ // descendants are. Break out of the loop.
174
+ return false;
175
+ }
176
+ }
177
+
178
+ /**
179
+ * Return the deepest cached node whose ID is a prefix of `targetID`.
180
+ */
181
+ function findDeepestCachedAncestor(targetID) {
182
+ deepestNodeSoFar = null;
183
+ ReactInstanceHandles.traverseAncestors(
184
+ targetID,
185
+ findDeepestCachedAncestorImpl
186
+ );
187
+
188
+ var foundNode = deepestNodeSoFar;
189
+ deepestNodeSoFar = null;
190
+ return foundNode;
191
+ }
192
+
161
193
  /**
162
194
  * Mounting is the process of initializing a React component by creatings its
163
195
  * representative DOM elements and inserting them into a supplied `container`.
164
196
  * Any prior content inside `container` is destroyed in the process.
165
197
  *
166
- * ReactMount.renderComponent(component, $('container'));
198
+ * ReactMount.renderComponent(
199
+ * component,
200
+ * document.getElementById('container')
201
+ * );
167
202
  *
168
203
  * <div id="container"> <-- Supplied `container`.
169
- * <div data-reactid=".r[3]"> <-- Rendered reactRoot of React
204
+ * <div data-reactid=".3"> <-- Rendered reactRoot of React
170
205
  * // ... component.
171
206
  * </div>
172
207
  * </div>
@@ -174,11 +209,6 @@ function purgeID(id) {
174
209
  * Inside of `container`, the first element rendered is the "reactRoot".
175
210
  */
176
211
  var ReactMount = {
177
- /**
178
- * Safety guard to prevent accidentally rendering over the entire HTML tree.
179
- */
180
- allowFullPageRender: false,
181
-
182
212
  /** Time spent generating markup. */
183
213
  totalInstantiationTime: 0,
184
214
 
@@ -203,30 +233,6 @@ var ReactMount = {
203
233
  renderCallback();
204
234
  },
205
235
 
206
- /**
207
- * Ensures that the top-level event delegation listener is set up. This will
208
- * be invoked some time before the first time any React component is rendered.
209
- * @param {DOMElement} container container we're rendering into
210
- *
211
- * @private
212
- */
213
- prepareEnvironmentForDOM: function(container) {
214
- ("production" !== process.env.NODE_ENV ? invariant(
215
- container && (
216
- container.nodeType === ELEMENT_NODE_TYPE ||
217
- container.nodeType === DOC_NODE_TYPE
218
- ),
219
- 'prepareEnvironmentForDOM(...): Target container is not a DOM element.'
220
- ) : invariant(container && (
221
- container.nodeType === ELEMENT_NODE_TYPE ||
222
- container.nodeType === DOC_NODE_TYPE
223
- )));
224
- var doc = container.nodeType === ELEMENT_NODE_TYPE ?
225
- container.ownerDocument :
226
- container;
227
- ReactEventEmitter.ensureListening(ReactMount.useTouchEvents, doc);
228
- },
229
-
230
236
  /**
231
237
  * Take a component that's already mounted into the DOM and replace its props
232
238
  * @param {ReactComponent} prevComponent component instance already in the DOM
@@ -254,13 +260,25 @@ var ReactMount = {
254
260
  },
255
261
 
256
262
  /**
257
- * Register a component into the instance map and start the events system.
263
+ * Register a component into the instance map and starts scroll value
264
+ * monitoring
258
265
  * @param {ReactComponent} nextComponent component instance to render
259
266
  * @param {DOMElement} container container to render into
260
267
  * @return {string} reactRoot ID prefix
261
268
  */
262
269
  _registerComponent: function(nextComponent, container) {
263
- ReactMount.prepareEnvironmentForDOM(container);
270
+ ("production" !== process.env.NODE_ENV ? invariant(
271
+ container && (
272
+ container.nodeType === ELEMENT_NODE_TYPE ||
273
+ container.nodeType === DOC_NODE_TYPE
274
+ ),
275
+ '_registerComponent(...): Target container is not a DOM element.'
276
+ ) : invariant(container && (
277
+ container.nodeType === ELEMENT_NODE_TYPE ||
278
+ container.nodeType === DOC_NODE_TYPE
279
+ )));
280
+
281
+ ReactEventEmitter.ensureScrollValueMonitoring();
264
282
 
265
283
  var reactRootID = ReactMount.registerContainer(container);
266
284
  instancesByReactRootID[reactRootID] = nextComponent;
@@ -274,25 +292,29 @@ var ReactMount = {
274
292
  * @param {boolean} shouldReuseMarkup if we should skip the markup insertion
275
293
  * @return {ReactComponent} nextComponent
276
294
  */
277
- _renderNewRootComponent: function(
278
- nextComponent,
279
- container,
280
- shouldReuseMarkup) {
281
- var reactRootID = ReactMount._registerComponent(nextComponent, container);
282
- nextComponent.mountComponentIntoNode(
283
- reactRootID,
284
- container,
285
- shouldReuseMarkup
286
- );
295
+ _renderNewRootComponent: ReactPerf.measure(
296
+ 'ReactMount',
297
+ '_renderNewRootComponent',
298
+ function(
299
+ nextComponent,
300
+ container,
301
+ shouldReuseMarkup) {
302
+ var reactRootID = ReactMount._registerComponent(nextComponent, container);
303
+ nextComponent.mountComponentIntoNode(
304
+ reactRootID,
305
+ container,
306
+ shouldReuseMarkup
307
+ );
287
308
 
288
- if ("production" !== process.env.NODE_ENV) {
289
- // Record the root element in case it later gets transplanted.
290
- rootElementsByReactRootID[reactRootID] =
291
- getReactRootElementInContainer(container);
292
- }
309
+ if ("production" !== process.env.NODE_ENV) {
310
+ // Record the root element in case it later gets transplanted.
311
+ rootElementsByReactRootID[reactRootID] =
312
+ getReactRootElementInContainer(container);
313
+ }
293
314
 
294
- return nextComponent;
295
- },
315
+ return nextComponent;
316
+ }
317
+ ),
296
318
 
297
319
  /**
298
320
  * Renders a React component into the DOM in the supplied `container`.
@@ -307,12 +329,12 @@ var ReactMount = {
307
329
  * @return {ReactComponent} Component instance rendered in `container`.
308
330
  */
309
331
  renderComponent: function(nextComponent, container, callback) {
310
- var registeredComponent = instancesByReactRootID[getReactRootID(container)];
332
+ var prevComponent = instancesByReactRootID[getReactRootID(container)];
311
333
 
312
- if (registeredComponent) {
313
- if (registeredComponent.constructor === nextComponent.constructor) {
334
+ if (prevComponent) {
335
+ if (shouldUpdateReactComponent(prevComponent, nextComponent)) {
314
336
  return ReactMount._updateRootComponent(
315
- registeredComponent,
337
+ prevComponent,
316
338
  nextComponent,
317
339
  container,
318
340
  callback
@@ -326,14 +348,14 @@ var ReactMount = {
326
348
  var containerHasReactMarkup =
327
349
  reactRootElement && ReactMount.isRenderedByReact(reactRootElement);
328
350
 
329
- var shouldReuseMarkup = containerHasReactMarkup && !registeredComponent;
351
+ var shouldReuseMarkup = containerHasReactMarkup && !prevComponent;
330
352
 
331
353
  var component = ReactMount._renderNewRootComponent(
332
354
  nextComponent,
333
355
  container,
334
356
  shouldReuseMarkup
335
357
  );
336
- callback && callback();
358
+ callback && callback.call(component);
337
359
  return component;
338
360
  },
339
361
 
@@ -360,12 +382,18 @@ var ReactMount = {
360
382
  * @return {ReactComponent} Component instance rendered in the container node.
361
383
  */
362
384
  constructAndRenderComponentByID: function(constructor, props, id) {
363
- return ReactMount.constructAndRenderComponent(constructor, props, $(id));
385
+ var domNode = document.getElementById(id);
386
+ ("production" !== process.env.NODE_ENV ? invariant(
387
+ domNode,
388
+ 'Tried to get element with id of "%s" but it is not present on the page.',
389
+ id
390
+ ) : invariant(domNode));
391
+ return ReactMount.constructAndRenderComponent(constructor, props, domNode);
364
392
  },
365
393
 
366
394
  /**
367
395
  * Registers a container node into which React components will be rendered.
368
- * This also creates the "reatRoot" ID that will be assigned to the element
396
+ * This also creates the "reactRoot" ID that will be assigned to the element
369
397
  * rendered within.
370
398
  *
371
399
  * @param {DOMElement} container DOM element to register as a container.
@@ -407,20 +435,6 @@ var ReactMount = {
407
435
  return true;
408
436
  },
409
437
 
410
- /**
411
- * @deprecated
412
- */
413
- unmountAndReleaseReactRootNode: function() {
414
- if ("production" !== process.env.NODE_ENV) {
415
- console.warn(
416
- 'unmountAndReleaseReactRootNode() has been renamed to ' +
417
- 'unmountComponentAtNode() and will be removed in the next ' +
418
- 'version of React.'
419
- );
420
- }
421
- return ReactMount.unmountComponentAtNode.apply(this, arguments);
422
- },
423
-
424
438
  /**
425
439
  * Unmounts a component and removes it from the DOM.
426
440
  *
@@ -533,39 +547,47 @@ var ReactMount = {
533
547
  },
534
548
 
535
549
  /**
536
- * Finds a node with the supplied `id` inside of the supplied `ancestorNode`.
537
- * Exploits the ID naming scheme to perform the search quickly.
550
+ * Finds a node with the supplied `targetID` inside of the supplied
551
+ * `ancestorNode`. Exploits the ID naming scheme to perform the search
552
+ * quickly.
538
553
  *
539
554
  * @param {DOMEventTarget} ancestorNode Search from this root.
540
- * @pararm {string} id ID of the DOM representation of the component.
541
- * @return {DOMEventTarget} DOM node with the supplied `id`.
555
+ * @pararm {string} targetID ID of the DOM representation of the component.
556
+ * @return {DOMEventTarget} DOM node with the supplied `targetID`.
542
557
  * @internal
543
558
  */
544
- findComponentRoot: function(ancestorNode, id) {
545
- var firstChildren = [ancestorNode.firstChild];
559
+ findComponentRoot: function(ancestorNode, targetID) {
560
+ var firstChildren = findComponentRootReusableArray;
546
561
  var childIndex = 0;
547
562
 
563
+ var deepestAncestor = findDeepestCachedAncestor(targetID) || ancestorNode;
564
+
565
+ firstChildren[0] = deepestAncestor.firstChild;
566
+ firstChildren.length = 1;
567
+
548
568
  while (childIndex < firstChildren.length) {
549
569
  var child = firstChildren[childIndex++];
570
+ var targetChild;
571
+
550
572
  while (child) {
551
573
  var childID = ReactMount.getID(child);
552
574
  if (childID) {
553
- if (id === childID) {
554
- return child;
555
- } else if (ReactInstanceHandles.isAncestorIDOf(childID, id)) {
575
+ // Even if we find the node we're looking for, we finish looping
576
+ // through its siblings to ensure they're cached so that we don't have
577
+ // to revisit this node again. Otherwise, we make n^2 calls to getID
578
+ // when visiting the many children of a single node in order.
579
+
580
+ if (targetID === childID) {
581
+ targetChild = child;
582
+ } else if (ReactInstanceHandles.isAncestorIDOf(childID, targetID)) {
556
583
  // If we find a child whose ID is an ancestor of the given ID,
557
584
  // then we can be sure that we only want to search the subtree
558
585
  // rooted at this child, so we can throw out the rest of the
559
586
  // search state.
560
587
  firstChildren.length = childIndex = 0;
561
588
  firstChildren.push(child.firstChild);
562
- break;
563
- } else {
564
- // TODO This should not be necessary if the ID hierarchy is
565
- // correct, but is occasionally necessary if the DOM has been
566
- // modified in unexpected ways.
567
- firstChildren.push(child.firstChild);
568
589
  }
590
+
569
591
  } else {
570
592
  // If this child had no ID, then there's a chance that it was
571
593
  // injected automatically by the browser, as when a `<table>`
@@ -574,22 +596,28 @@ var ReactMount = {
574
596
  // branch, but not before examining the other siblings.
575
597
  firstChildren.push(child.firstChild);
576
598
  }
599
+
577
600
  child = child.nextSibling;
578
601
  }
579
- }
580
602
 
581
- if ("production" !== process.env.NODE_ENV) {
582
- console.error(
583
- 'Error while invoking `findComponentRoot` with the following ' +
584
- 'ancestor node:',
585
- ancestorNode
586
- );
603
+ if (targetChild) {
604
+ // Emptying firstChildren/findComponentRootReusableArray is
605
+ // not necessary for correctness, but it helps the GC reclaim
606
+ // any nodes that were left at the end of the search.
607
+ firstChildren.length = 0;
608
+
609
+ return targetChild;
610
+ }
587
611
  }
612
+
613
+ firstChildren.length = 0;
614
+
588
615
  ("production" !== process.env.NODE_ENV ? invariant(
589
616
  false,
590
617
  'findComponentRoot(..., %s): Unable to find element. This probably ' +
591
- 'means the DOM was unexpectedly mutated (e.g. by the browser).',
592
- id,
618
+ 'means the DOM was unexpectedly mutated (e.g., by the browser). ' +
619
+ 'Try inspecting the child nodes of the element with React ID `%s`.',
620
+ targetID,
593
621
  ReactMount.getID(ancestorNode)
594
622
  ) : invariant(false));
595
623
  },
@@ -599,8 +627,6 @@ var ReactMount = {
599
627
  * React ID utilities.
600
628
  */
601
629
 
602
- ATTR_NAME: ATTR_NAME,
603
-
604
630
  getReactRootID: getReactRootID,
605
631
 
606
632
  getID: getID,
@@ -609,9 +635,7 @@ var ReactMount = {
609
635
 
610
636
  getNode: getNode,
611
637
 
612
- purgeID: purgeID,
613
-
614
- injection: {}
638
+ purgeID: purgeID
615
639
  };
616
640
 
617
641
  module.exports = ReactMount;