react 0.8.0 → 0.10.0

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 (160) hide show
  1. package/README.md +0 -8
  2. package/addons.js +0 -3
  3. package/lib/AutoFocusMixin.js +32 -0
  4. package/lib/CSSCore.js +23 -22
  5. package/lib/CSSProperty.js +32 -1
  6. package/lib/CSSPropertyOperations.js +1 -1
  7. package/lib/ChangeEventPlugin.js +27 -5
  8. package/lib/ClientReactRootIndex.js +30 -0
  9. package/lib/CompositionEventPlugin.js +58 -10
  10. package/lib/DOMChildrenOperations.js +39 -3
  11. package/lib/DOMProperty.js +9 -5
  12. package/lib/DOMPropertyOperations.js +21 -8
  13. package/lib/Danger.js +9 -8
  14. package/lib/DefaultDOMPropertyConfig.js +23 -14
  15. package/lib/DefaultEventPluginOrder.js +1 -1
  16. package/lib/EnterLeaveEventPlugin.js +38 -5
  17. package/lib/EventConstants.js +4 -1
  18. package/lib/EventListener.js +42 -34
  19. package/lib/EventPluginHub.js +118 -13
  20. package/lib/EventPluginRegistry.js +62 -18
  21. package/lib/EventPluginUtils.js +33 -4
  22. package/lib/EventPropagators.js +7 -43
  23. package/lib/ExecutionEnvironment.js +4 -1
  24. package/lib/LinkedStateMixin.js +1 -1
  25. package/lib/LinkedValueUtils.js +160 -0
  26. package/lib/MobileSafariClickEventPlugin.js +1 -1
  27. package/lib/PooledClass.js +7 -1
  28. package/lib/React.js +30 -4
  29. package/lib/ReactBrowserComponentMixin.js +42 -0
  30. package/lib/ReactCSSTransitionGroup.js +65 -0
  31. package/lib/{ReactTransitionableChild.js → ReactCSSTransitionGroupChild.js} +22 -36
  32. package/lib/ReactChildren.js +4 -4
  33. package/lib/ReactComponent.js +163 -83
  34. package/lib/ReactComponentBrowserEnvironment.js +55 -71
  35. package/lib/ReactCompositeComponent.js +686 -119
  36. package/lib/ReactContext.js +67 -0
  37. package/lib/ReactCurrentOwner.js +1 -1
  38. package/lib/ReactDOM.js +19 -6
  39. package/lib/ReactDOMButton.js +6 -1
  40. package/lib/ReactDOMComponent.js +66 -24
  41. package/lib/ReactDOMForm.js +13 -3
  42. package/lib/ReactDOMIDOperations.js +106 -61
  43. package/lib/ReactDOMImg.js +61 -0
  44. package/lib/ReactDOMInput.js +28 -15
  45. package/lib/ReactDOMOption.js +13 -8
  46. package/lib/ReactDOMSelect.js +38 -18
  47. package/lib/ReactDOMSelection.js +1 -1
  48. package/lib/ReactDOMTextarea.js +19 -11
  49. package/lib/ReactDefaultBatchingStrategy.js +1 -1
  50. package/lib/ReactDefaultInjection.js +60 -26
  51. package/lib/ReactDefaultPerf.js +208 -371
  52. package/lib/ReactDefaultPerfAnalysis.js +199 -0
  53. package/lib/ReactErrorUtils.js +6 -15
  54. package/lib/ReactEventEmitter.js +144 -146
  55. package/lib/ReactEventEmitterMixin.js +1 -33
  56. package/lib/ReactEventTopLevelCallback.js +75 -15
  57. package/lib/ReactInjection.js +43 -0
  58. package/lib/ReactInputSelection.js +3 -2
  59. package/lib/ReactInstanceHandles.js +36 -20
  60. package/lib/ReactLink.js +2 -2
  61. package/lib/ReactMarkupChecksum.js +1 -1
  62. package/lib/ReactMount.js +136 -104
  63. package/lib/ReactMountReady.js +2 -2
  64. package/lib/ReactMultiChild.js +40 -49
  65. package/lib/ReactMultiChildUpdateTypes.js +3 -1
  66. package/lib/ReactOwner.js +17 -4
  67. package/lib/ReactPerf.js +6 -9
  68. package/lib/ReactPropTransferer.js +41 -22
  69. package/lib/ReactPropTypeLocationNames.js +31 -0
  70. package/lib/{ReactComponentEnvironment.js → ReactPropTypeLocations.js} +11 -6
  71. package/lib/ReactPropTypes.js +249 -48
  72. package/lib/ReactPutListenerQueue.js +61 -0
  73. package/lib/ReactReconcileTransaction.js +28 -7
  74. package/lib/ReactRootIndex.js +36 -0
  75. package/lib/ReactServerRendering.js +46 -19
  76. package/lib/ReactServerRenderingTransaction.js +116 -0
  77. package/lib/ReactStateSetters.js +1 -1
  78. package/lib/ReactTestUtils.js +394 -0
  79. package/lib/ReactTextComponent.js +33 -6
  80. package/lib/{ReactTransitionKeySet.js → ReactTransitionChildMapping.js} +43 -48
  81. package/lib/ReactTransitionEvents.js +1 -1
  82. package/lib/ReactTransitionGroup.js +133 -58
  83. package/lib/ReactUpdates.js +15 -12
  84. package/lib/ReactWithAddons.js +15 -3
  85. package/lib/SelectEventPlugin.js +23 -40
  86. package/lib/ServerReactRootIndex.js +36 -0
  87. package/lib/SimpleEventPlugin.js +55 -7
  88. package/lib/SyntheticClipboardEvent.js +8 -2
  89. package/lib/SyntheticCompositionEvent.js +1 -1
  90. package/lib/SyntheticDragEvent.js +44 -0
  91. package/lib/SyntheticEvent.js +3 -2
  92. package/lib/SyntheticFocusEvent.js +1 -1
  93. package/lib/SyntheticKeyboardEvent.js +5 -3
  94. package/lib/SyntheticMouseEvent.js +1 -1
  95. package/lib/SyntheticTouchEvent.js +1 -1
  96. package/lib/SyntheticUIEvent.js +1 -1
  97. package/lib/SyntheticWheelEvent.js +11 -8
  98. package/lib/Transaction.js +62 -37
  99. package/lib/ViewportMetrics.js +1 -1
  100. package/lib/accumulate.js +1 -1
  101. package/lib/adler32.js +1 -1
  102. package/lib/cloneWithProps.js +59 -0
  103. package/lib/containsNode.js +1 -1
  104. package/lib/copyProperties.js +1 -1
  105. package/lib/createArrayFrom.js +11 -14
  106. package/lib/createFullPageComponent.js +63 -0
  107. package/lib/createNodesFromMarkup.js +1 -1
  108. package/lib/createObjectFrom.js +1 -1
  109. package/lib/cx.js +3 -3
  110. package/lib/dangerousStyleValue.js +1 -1
  111. package/lib/emptyFunction.js +1 -1
  112. package/lib/emptyObject.js +27 -0
  113. package/lib/escapeTextForBrowser.js +1 -1
  114. package/lib/flattenChildren.js +6 -3
  115. package/lib/focusNode.js +33 -0
  116. package/lib/forEachAccumulated.js +1 -1
  117. package/lib/getActiveElement.js +5 -4
  118. package/lib/getEventKey.js +85 -0
  119. package/lib/getEventTarget.js +1 -1
  120. package/lib/getMarkupWrap.js +11 -1
  121. package/lib/getNodeForCharacterOffset.js +1 -1
  122. package/lib/getReactRootElementInContainer.js +1 -1
  123. package/lib/getTextContentAccessor.js +6 -4
  124. package/lib/getUnboundedScrollPosition.js +3 -3
  125. package/lib/hyphenate.js +1 -1
  126. package/lib/instantiateReactComponent.js +70 -0
  127. package/lib/invariant.js +20 -12
  128. package/lib/isEventSupported.js +8 -12
  129. package/lib/isNode.js +2 -2
  130. package/lib/isTextInputElement.js +1 -1
  131. package/lib/isTextNode.js +1 -1
  132. package/lib/joinClasses.js +1 -1
  133. package/lib/keyMirror.js +1 -1
  134. package/lib/keyOf.js +1 -1
  135. package/lib/memoizeStringOnly.js +1 -1
  136. package/lib/merge.js +1 -1
  137. package/lib/mergeHelpers.js +6 -7
  138. package/lib/mergeInto.js +1 -1
  139. package/lib/mixInto.js +1 -1
  140. package/lib/monitorCodeUse.js +37 -0
  141. package/lib/objMap.js +1 -1
  142. package/lib/objMapKeyVal.js +1 -1
  143. package/lib/onlyChild.js +43 -0
  144. package/lib/performanceNow.js +1 -1
  145. package/lib/shallowEqual.js +1 -1
  146. package/lib/shouldUpdateReactComponent.js +61 -0
  147. package/lib/toArray.js +75 -0
  148. package/lib/traverseAllChildren.js +72 -9
  149. package/lib/update.js +159 -0
  150. package/lib/warning.js +48 -0
  151. package/package.json +3 -3
  152. package/react.js +0 -3
  153. package/ReactJSErrors.js +0 -40
  154. package/lib/$.js +0 -46
  155. package/lib/CallbackRegistry.js +0 -91
  156. package/lib/LinkedValueMixin.js +0 -68
  157. package/lib/ex.js +0 -49
  158. package/lib/filterAttributes.js +0 -45
  159. package/lib/ge.js +0 -76
  160. package/lib/mutateHTMLNodeWithMarkup.js +0 -100
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Copyright 2013 Facebook, Inc.
2
+ * Copyright 2013-2014 Facebook, Inc.
3
3
  *
4
4
  * Licensed under the Apache License, Version 2.0 (the "License");
5
5
  * you may not use this file except in compliance with the License.
@@ -23,11 +23,11 @@
23
23
  var ReactDOMIDOperations = require("./ReactDOMIDOperations");
24
24
  var ReactMarkupChecksum = require("./ReactMarkupChecksum");
25
25
  var ReactMount = require("./ReactMount");
26
+ var ReactPerf = require("./ReactPerf");
26
27
  var ReactReconcileTransaction = require("./ReactReconcileTransaction");
27
28
 
28
29
  var getReactRootElementInContainer = require("./getReactRootElementInContainer");
29
30
  var invariant = require("./invariant");
30
- var mutateHTMLNodeWithMarkup = require("./mutateHTMLNodeWithMarkup");
31
31
 
32
32
 
33
33
  var ELEMENT_NODE_TYPE = 1;
@@ -39,29 +39,9 @@ var DOC_NODE_TYPE = 9;
39
39
  * the browser context.
40
40
  */
41
41
  var ReactComponentBrowserEnvironment = {
42
- /**
43
- * Mixed into every component instance.
44
- */
45
- Mixin: {
46
- /**
47
- * Returns the DOM node rendered by this component.
48
- *
49
- * @return {DOMElement} The root node of this component.
50
- * @final
51
- * @protected
52
- */
53
- getDOMNode: function() {
54
- ("production" !== process.env.NODE_ENV ? invariant(
55
- this.isMounted(),
56
- 'getDOMNode(): A component must be mounted to have a DOM node.'
57
- ) : invariant(this.isMounted()));
58
- return ReactMount.getNode(this._rootNodeID);
59
- }
60
- },
61
-
62
42
  ReactReconcileTransaction: ReactReconcileTransaction,
63
43
 
64
- DOMIDOperations: ReactDOMIDOperations,
44
+ BackendIDOperations: ReactDOMIDOperations,
65
45
 
66
46
  /**
67
47
  * If a particular environment requires that some resources be cleaned up,
@@ -80,61 +60,65 @@ var ReactComponentBrowserEnvironment = {
80
60
  * @param {boolean} shouldReuseMarkup Should reuse the existing markup in the
81
61
  * container if possible.
82
62
  */
83
- mountImageIntoNode: function(markup, container, shouldReuseMarkup) {
84
- ("production" !== process.env.NODE_ENV ? invariant(
85
- container && (
63
+ mountImageIntoNode: ReactPerf.measure(
64
+ 'ReactComponentBrowserEnvironment',
65
+ 'mountImageIntoNode',
66
+ function(markup, container, shouldReuseMarkup) {
67
+ ("production" !== process.env.NODE_ENV ? invariant(
68
+ container && (
69
+ container.nodeType === ELEMENT_NODE_TYPE ||
70
+ container.nodeType === DOC_NODE_TYPE
71
+ ),
72
+ 'mountComponentIntoNode(...): Target container is not valid.'
73
+ ) : invariant(container && (
86
74
  container.nodeType === ELEMENT_NODE_TYPE ||
87
- container.nodeType === DOC_NODE_TYPE && ReactMount.allowFullPageRender
88
- ),
89
- 'mountComponentIntoNode(...): Target container is not valid.'
90
- ) : invariant(container && (
91
- container.nodeType === ELEMENT_NODE_TYPE ||
92
- container.nodeType === DOC_NODE_TYPE && ReactMount.allowFullPageRender
93
- )));
94
- if (shouldReuseMarkup) {
95
- if (ReactMarkupChecksum.canReuseMarkup(
96
- markup,
97
- getReactRootElementInContainer(container))) {
98
- return;
99
- } else {
100
- if ("production" !== process.env.NODE_ENV) {
101
- console.warn(
102
- 'React attempted to use reuse markup in a container but the ' +
103
- 'checksum was invalid. This generally means that you are using ' +
104
- 'server rendering and the markup generated on the server was ' +
105
- 'not what the client was expecting. React injected new markup ' +
106
- 'to compensate which works but you have lost many of the ' +
107
- 'benefits of server rendering. Instead, figure out why the ' +
108
- 'markup being generated is different on the client or server.'
109
- );
75
+ container.nodeType === DOC_NODE_TYPE
76
+ )));
77
+
78
+ if (shouldReuseMarkup) {
79
+ if (ReactMarkupChecksum.canReuseMarkup(
80
+ markup,
81
+ getReactRootElementInContainer(container))) {
82
+ return;
83
+ } else {
84
+ ("production" !== process.env.NODE_ENV ? invariant(
85
+ container.nodeType !== DOC_NODE_TYPE,
86
+ 'You\'re trying to render a component to the document using ' +
87
+ 'server rendering but the checksum was invalid. This usually ' +
88
+ 'means you rendered a different component type or props on ' +
89
+ 'the client from the one on the server, or your render() ' +
90
+ 'methods are impure. React cannot handle this case due to ' +
91
+ 'cross-browser quirks by rendering at the document root. You ' +
92
+ 'should look for environment dependent code in your components ' +
93
+ 'and ensure the props are the same client and server side.'
94
+ ) : invariant(container.nodeType !== DOC_NODE_TYPE));
95
+
96
+ if ("production" !== process.env.NODE_ENV) {
97
+ console.warn(
98
+ 'React attempted to use reuse markup in a container but the ' +
99
+ 'checksum was invalid. This generally means that you are ' +
100
+ 'using server rendering and the markup generated on the ' +
101
+ 'server was not what the client was expecting. React injected' +
102
+ 'new markup to compensate which works but you have lost many ' +
103
+ 'of the benefits of server rendering. Instead, figure out ' +
104
+ 'why the markup being generated is different on the client ' +
105
+ 'or server.'
106
+ );
107
+ }
110
108
  }
111
109
  }
112
- }
113
110
 
114
- // You can't naively set the innerHTML of the entire document. You need
115
- // to mutate documentElement which requires doing some crazy tricks. See
116
- // mutateHTMLNodeWithMarkup()
117
- if (container.nodeType === DOC_NODE_TYPE) {
118
- mutateHTMLNodeWithMarkup(container.documentElement, markup);
119
- return;
120
- }
111
+ ("production" !== process.env.NODE_ENV ? invariant(
112
+ container.nodeType !== DOC_NODE_TYPE,
113
+ 'You\'re trying to render a component to the document but ' +
114
+ 'you didn\'t use server rendering. We can\'t do this ' +
115
+ 'without using server rendering due to cross-browser quirks. ' +
116
+ 'See renderComponentToString() for server rendering.'
117
+ ) : invariant(container.nodeType !== DOC_NODE_TYPE));
121
118
 
122
- // Asynchronously inject markup by ensuring that the container is not in
123
- // the document when settings its `innerHTML`.
124
- var parent = container.parentNode;
125
- if (parent) {
126
- var next = container.nextSibling;
127
- parent.removeChild(container);
128
- container.innerHTML = markup;
129
- if (next) {
130
- parent.insertBefore(container, next);
131
- } else {
132
- parent.appendChild(container);
133
- }
134
- } else {
135
119
  container.innerHTML = markup;
136
120
  }
137
- }
121
+ )
138
122
  };
139
123
 
140
124
  module.exports = ReactComponentBrowserEnvironment;
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Copyright 2013 Facebook, Inc.
2
+ * Copyright 2013-2014 Facebook, Inc.
3
3
  *
4
4
  * Licensed under the Apache License, Version 2.0 (the "License");
5
5
  * you may not use this file except in compliance with the License.
@@ -19,18 +19,25 @@
19
19
  "use strict";
20
20
 
21
21
  var ReactComponent = require("./ReactComponent");
22
+ var ReactContext = require("./ReactContext");
22
23
  var ReactCurrentOwner = require("./ReactCurrentOwner");
23
24
  var ReactErrorUtils = require("./ReactErrorUtils");
24
25
  var ReactOwner = require("./ReactOwner");
25
26
  var ReactPerf = require("./ReactPerf");
26
27
  var ReactPropTransferer = require("./ReactPropTransferer");
28
+ var ReactPropTypeLocations = require("./ReactPropTypeLocations");
29
+ var ReactPropTypeLocationNames = require("./ReactPropTypeLocationNames");
27
30
  var ReactUpdates = require("./ReactUpdates");
28
31
 
32
+ var instantiateReactComponent = require("./instantiateReactComponent");
29
33
  var invariant = require("./invariant");
30
34
  var keyMirror = require("./keyMirror");
31
35
  var merge = require("./merge");
32
36
  var mixInto = require("./mixInto");
37
+ var monitorCodeUse = require("./monitorCodeUse");
33
38
  var objMap = require("./objMap");
39
+ var shouldUpdateReactComponent = require("./shouldUpdateReactComponent");
40
+ var warning = require("./warning");
34
41
 
35
42
  /**
36
43
  * Policies that describe methods in `ReactCompositeComponentInterface`.
@@ -57,6 +64,9 @@ var SpecPolicy = keyMirror({
57
64
  DEFINE_MANY_MERGED: null
58
65
  });
59
66
 
67
+
68
+ var injectedMixins = [];
69
+
60
70
  /**
61
71
  * Composite components are higher-level components that compose other composite
62
72
  * or native components.
@@ -89,15 +99,38 @@ var ReactCompositeComponentInterface = {
89
99
  */
90
100
  mixins: SpecPolicy.DEFINE_MANY,
91
101
 
102
+ /**
103
+ * An object containing properties and methods that should be defined on
104
+ * the component's constructor instead of its prototype (static methods).
105
+ *
106
+ * @type {object}
107
+ * @optional
108
+ */
109
+ statics: SpecPolicy.DEFINE_MANY,
110
+
92
111
  /**
93
112
  * Definition of prop types for this component.
94
113
  *
95
114
  * @type {object}
96
115
  * @optional
97
116
  */
98
- propTypes: SpecPolicy.DEFINE_ONCE,
117
+ propTypes: SpecPolicy.DEFINE_MANY,
99
118
 
119
+ /**
120
+ * Definition of context types for this component.
121
+ *
122
+ * @type {object}
123
+ * @optional
124
+ */
125
+ contextTypes: SpecPolicy.DEFINE_MANY,
100
126
 
127
+ /**
128
+ * Definition of context types this component sets for its children.
129
+ *
130
+ * @type {object}
131
+ * @optional
132
+ */
133
+ childContextTypes: SpecPolicy.DEFINE_MANY,
101
134
 
102
135
  // ==== Definition methods ====
103
136
 
@@ -129,6 +162,12 @@ var ReactCompositeComponentInterface = {
129
162
  */
130
163
  getInitialState: SpecPolicy.DEFINE_MANY_MERGED,
131
164
 
165
+ /**
166
+ * @return {object}
167
+ * @optional
168
+ */
169
+ getChildContext: SpecPolicy.DEFINE_MANY_MERGED,
170
+
132
171
  /**
133
172
  * Uses props from `this.props` and state from `this.state` to render the
134
173
  * structure of the component.
@@ -178,7 +217,7 @@ var ReactCompositeComponentInterface = {
178
217
  * Use this as an opportunity to react to a prop transition by updating the
179
218
  * state using `this.setState`. Current props are accessed via `this.props`.
180
219
  *
181
- * componentWillReceiveProps: function(nextProps) {
220
+ * componentWillReceiveProps: function(nextProps, nextContext) {
182
221
  * this.setState({
183
222
  * likesIncreasing: nextProps.likeCount > this.props.likeCount
184
223
  * });
@@ -195,17 +234,21 @@ var ReactCompositeComponentInterface = {
195
234
 
196
235
  /**
197
236
  * Invoked while deciding if the component should be updated as a result of
198
- * receiving new props and state.
237
+ * receiving new props, state and/or context.
199
238
  *
200
239
  * Use this as an opportunity to `return false` when you're certain that the
201
- * transition to the new props and state will not require a component update.
240
+ * transition to the new props/state/context will not require a component
241
+ * update.
202
242
  *
203
- * shouldComponentUpdate: function(nextProps, nextState) {
204
- * return !equal(nextProps, this.props) || !equal(nextState, this.state);
243
+ * shouldComponentUpdate: function(nextProps, nextState, nextContext) {
244
+ * return !equal(nextProps, this.props) ||
245
+ * !equal(nextState, this.state) ||
246
+ * !equal(nextContext, this.context);
205
247
  * }
206
248
  *
207
249
  * @param {object} nextProps
208
250
  * @param {?object} nextState
251
+ * @param {?object} nextContext
209
252
  * @return {boolean} True if the component should update.
210
253
  * @optional
211
254
  */
@@ -213,7 +256,8 @@ var ReactCompositeComponentInterface = {
213
256
 
214
257
  /**
215
258
  * Invoked when the component is about to update due to a transition from
216
- * `this.props` and `this.state` to `nextProps` and `nextState`.
259
+ * `this.props`, `this.state` and `this.context` to `nextProps`, `nextState`
260
+ * and `nextContext`.
217
261
  *
218
262
  * Use this as an opportunity to perform preparation before an update occurs.
219
263
  *
@@ -221,6 +265,7 @@ var ReactCompositeComponentInterface = {
221
265
  *
222
266
  * @param {object} nextProps
223
267
  * @param {?object} nextState
268
+ * @param {?object} nextContext
224
269
  * @param {ReactReconcileTransaction} transaction
225
270
  * @optional
226
271
  */
@@ -234,6 +279,7 @@ var ReactCompositeComponentInterface = {
234
279
  *
235
280
  * @param {object} prevProps
236
281
  * @param {?object} prevState
282
+ * @param {?object} prevContext
237
283
  * @param {DOMElement} rootNode DOM element representing the component.
238
284
  * @optional
239
285
  */
@@ -273,25 +319,73 @@ var ReactCompositeComponentInterface = {
273
319
  /**
274
320
  * Mapping from class specification keys to special processing functions.
275
321
  *
276
- * Although these are declared in the specification when defining classes
277
- * using `React.createClass`, they will not be on the component's prototype.
322
+ * Although these are declared like instance properties in the specification
323
+ * when defining classes using `React.createClass`, they are actually static
324
+ * and are accessible on the constructor instead of the prototype. Despite
325
+ * being static, they must be defined outside of the "statics" key under
326
+ * which all other static methods are defined.
278
327
  */
279
328
  var RESERVED_SPEC_KEYS = {
280
- displayName: function(Constructor, displayName) {
281
- Constructor.displayName = displayName;
329
+ displayName: function(ConvenienceConstructor, displayName) {
330
+ ConvenienceConstructor.componentConstructor.displayName = displayName;
282
331
  },
283
- mixins: function(Constructor, mixins) {
332
+ mixins: function(ConvenienceConstructor, mixins) {
284
333
  if (mixins) {
285
334
  for (var i = 0; i < mixins.length; i++) {
286
- mixSpecIntoComponent(Constructor, mixins[i]);
335
+ mixSpecIntoComponent(ConvenienceConstructor, mixins[i]);
287
336
  }
288
337
  }
289
338
  },
290
- propTypes: function(Constructor, propTypes) {
291
- Constructor.propTypes = propTypes;
339
+ childContextTypes: function(ConvenienceConstructor, childContextTypes) {
340
+ var Constructor = ConvenienceConstructor.componentConstructor;
341
+ validateTypeDef(
342
+ Constructor,
343
+ childContextTypes,
344
+ ReactPropTypeLocations.childContext
345
+ );
346
+ Constructor.childContextTypes = merge(
347
+ Constructor.childContextTypes,
348
+ childContextTypes
349
+ );
350
+ },
351
+ contextTypes: function(ConvenienceConstructor, contextTypes) {
352
+ var Constructor = ConvenienceConstructor.componentConstructor;
353
+ validateTypeDef(
354
+ Constructor,
355
+ contextTypes,
356
+ ReactPropTypeLocations.context
357
+ );
358
+ Constructor.contextTypes = merge(Constructor.contextTypes, contextTypes);
359
+ },
360
+ propTypes: function(ConvenienceConstructor, propTypes) {
361
+ var Constructor = ConvenienceConstructor.componentConstructor;
362
+ validateTypeDef(
363
+ Constructor,
364
+ propTypes,
365
+ ReactPropTypeLocations.prop
366
+ );
367
+ Constructor.propTypes = merge(Constructor.propTypes, propTypes);
368
+ },
369
+ statics: function(ConvenienceConstructor, statics) {
370
+ mixStaticSpecIntoComponent(ConvenienceConstructor, statics);
292
371
  }
293
372
  };
294
373
 
374
+ function validateTypeDef(Constructor, typeDef, location) {
375
+ for (var propName in typeDef) {
376
+ if (typeDef.hasOwnProperty(propName)) {
377
+ ("production" !== process.env.NODE_ENV ? invariant(
378
+ typeof typeDef[propName] == 'function',
379
+ '%s: %s type `%s` is invalid; it must be a function, usually from ' +
380
+ 'React.PropTypes.',
381
+ Constructor.displayName || 'ReactCompositeComponent',
382
+ ReactPropTypeLocationNames[location],
383
+ propName
384
+ ) : invariant(typeof typeDef[propName] == 'function'));
385
+ }
386
+ }
387
+ }
388
+
295
389
  function validateMethodOverride(proto, name) {
296
390
  var specPolicy = ReactCompositeComponentInterface[name];
297
391
 
@@ -320,7 +414,6 @@ function validateMethodOverride(proto, name) {
320
414
  }
321
415
  }
322
416
 
323
-
324
417
  function validateLifeCycleOnReplaceState(instance) {
325
418
  var compositeLifeCycleState = instance._compositeLifeCycleState;
326
419
  ("production" !== process.env.NODE_ENV ? invariant(
@@ -344,17 +437,30 @@ function validateLifeCycleOnReplaceState(instance) {
344
437
  * Custom version of `mixInto` which handles policy validation and reserved
345
438
  * specification keys when building `ReactCompositeComponent` classses.
346
439
  */
347
- function mixSpecIntoComponent(Constructor, spec) {
440
+ function mixSpecIntoComponent(ConvenienceConstructor, spec) {
441
+ ("production" !== process.env.NODE_ENV ? invariant(
442
+ !isValidClass(spec),
443
+ 'ReactCompositeComponent: You\'re attempting to ' +
444
+ 'use a component class as a mixin. Instead, just use a regular object.'
445
+ ) : invariant(!isValidClass(spec)));
446
+ ("production" !== process.env.NODE_ENV ? invariant(
447
+ !ReactComponent.isValidComponent(spec),
448
+ 'ReactCompositeComponent: You\'re attempting to ' +
449
+ 'use a component as a mixin. Instead, just use a regular object.'
450
+ ) : invariant(!ReactComponent.isValidComponent(spec)));
451
+
452
+ var Constructor = ConvenienceConstructor.componentConstructor;
348
453
  var proto = Constructor.prototype;
349
454
  for (var name in spec) {
350
455
  var property = spec[name];
351
- if (!spec.hasOwnProperty(name) || !property) {
456
+ if (!spec.hasOwnProperty(name)) {
352
457
  continue;
353
458
  }
459
+
354
460
  validateMethodOverride(proto, name);
355
461
 
356
462
  if (RESERVED_SPEC_KEYS.hasOwnProperty(name)) {
357
- RESERVED_SPEC_KEYS[name](Constructor, property);
463
+ RESERVED_SPEC_KEYS[name](ConvenienceConstructor, property);
358
464
  } else {
359
465
  // Setup methods on prototype:
360
466
  // The following member methods should not be automatically bound:
@@ -362,7 +468,7 @@ function mixSpecIntoComponent(Constructor, spec) {
362
468
  // 2. Overridden methods (that were mixed in).
363
469
  var isCompositeComponentMethod = name in ReactCompositeComponentInterface;
364
470
  var isInherited = name in proto;
365
- var markedDontBind = property.__reactDontBind;
471
+ var markedDontBind = property && property.__reactDontBind;
366
472
  var isFunction = typeof property === 'function';
367
473
  var shouldAutoBind =
368
474
  isFunction &&
@@ -394,6 +500,37 @@ function mixSpecIntoComponent(Constructor, spec) {
394
500
  }
395
501
  }
396
502
 
503
+ function mixStaticSpecIntoComponent(ConvenienceConstructor, statics) {
504
+ if (!statics) {
505
+ return;
506
+ }
507
+ for (var name in statics) {
508
+ var property = statics[name];
509
+ if (!statics.hasOwnProperty(name)) {
510
+ return;
511
+ }
512
+
513
+ var isInherited = name in ConvenienceConstructor;
514
+ var result = property;
515
+ if (isInherited) {
516
+ var existingProperty = ConvenienceConstructor[name];
517
+ var existingType = typeof existingProperty;
518
+ var propertyType = typeof property;
519
+ ("production" !== process.env.NODE_ENV ? invariant(
520
+ existingType === 'function' && propertyType === 'function',
521
+ 'ReactCompositeComponent: You are attempting to define ' +
522
+ '`%s` on your component more than once, but that is only supported ' +
523
+ 'for functions, which are chained together. This conflict may be ' +
524
+ 'due to a mixin.',
525
+ name
526
+ ) : invariant(existingType === 'function' && propertyType === 'function'));
527
+ result = createChainedFunction(existingProperty, property);
528
+ }
529
+ ConvenienceConstructor[name] = result;
530
+ ConvenienceConstructor.componentConstructor[name] = result;
531
+ }
532
+ }
533
+
397
534
  /**
398
535
  * Merge two objects, but throw if both contain the same key.
399
536
  *
@@ -429,10 +566,14 @@ function mergeObjectsWithNoDuplicateKeys(one, two) {
429
566
  */
430
567
  function createMergedResultFunction(one, two) {
431
568
  return function mergedResult() {
432
- return mergeObjectsWithNoDuplicateKeys(
433
- one.apply(this, arguments),
434
- two.apply(this, arguments)
435
- );
569
+ var a = one.apply(this, arguments);
570
+ var b = two.apply(this, arguments);
571
+ if (a == null) {
572
+ return b;
573
+ } else if (b == null) {
574
+ return a;
575
+ }
576
+ return mergeObjectsWithNoDuplicateKeys(a, b);
436
577
  };
437
578
  }
438
579
 
@@ -451,6 +592,203 @@ function createChainedFunction(one, two) {
451
592
  };
452
593
  }
453
594
 
595
+ if ("production" !== process.env.NODE_ENV) {
596
+
597
+ var unmountedPropertyWhitelist = {
598
+ constructor: true,
599
+ construct: true,
600
+ isOwnedBy: true, // should be deprecated but can have code mod (internal)
601
+ type: true,
602
+ props: true,
603
+ // currently private but belong on the descriptor and are valid for use
604
+ // inside the framework:
605
+ __keyValidated__: true,
606
+ _owner: true,
607
+ _currentContext: true
608
+ };
609
+
610
+ var componentInstanceProperties = {
611
+ __keyValidated__: true,
612
+ __keySetters: true,
613
+ _compositeLifeCycleState: true,
614
+ _currentContext: true,
615
+ _defaultProps: true,
616
+ _instance: true,
617
+ _lifeCycleState: true,
618
+ _mountDepth: true,
619
+ _owner: true,
620
+ _pendingCallbacks: true,
621
+ _pendingContext: true,
622
+ _pendingForceUpdate: true,
623
+ _pendingOwner: true,
624
+ _pendingProps: true,
625
+ _pendingState: true,
626
+ _renderedComponent: true,
627
+ _rootNodeID: true,
628
+ context: true,
629
+ props: true,
630
+ refs: true,
631
+ state: true,
632
+
633
+ // These are known instance properties coming from other sources
634
+ _pendingQueries: true,
635
+ _queryPropListeners: true,
636
+ queryParams: true
637
+
638
+ };
639
+
640
+ var hasWarnedOnComponentType = {};
641
+
642
+ var warningStackCounter = 0;
643
+
644
+ var issueMembraneWarning = function(instance, key) {
645
+ var isWhitelisted = unmountedPropertyWhitelist.hasOwnProperty(key);
646
+ if (warningStackCounter > 0 || isWhitelisted) {
647
+ return;
648
+ }
649
+ var name = instance.constructor.displayName || 'Unknown';
650
+ var owner = ReactCurrentOwner.current;
651
+ var ownerName = (owner && owner.constructor.displayName) || 'Unknown';
652
+ var warningKey = key + '|' + name + '|' + ownerName;
653
+ if (hasWarnedOnComponentType.hasOwnProperty(warningKey)) {
654
+ // We have already warned for this combination. Skip it this time.
655
+ return;
656
+ }
657
+ hasWarnedOnComponentType[warningKey] = true;
658
+
659
+ var context = owner ? ' in ' + ownerName + '.' : ' at the top level.';
660
+ var staticMethodExample = '<' + name + ' />.type.' + key + '(...)';
661
+
662
+ monitorCodeUse('react_descriptor_property_access', { component: name });
663
+ console.warn(
664
+ 'Invalid access to component property "' + key + '" on ' + name +
665
+ context + ' See http://fb.me/react-warning-descriptors .' +
666
+ ' Use a static method instead: ' + staticMethodExample
667
+ );
668
+ };
669
+
670
+ var wrapInMembraneFunction = function(fn, thisBinding) {
671
+ if (fn.__reactMembraneFunction && fn.__reactMembraneSelf === thisBinding) {
672
+ return fn.__reactMembraneFunction;
673
+ }
674
+ return fn.__reactMembraneFunction = function() {
675
+ /**
676
+ * By getting this function, you've already received a warning. The
677
+ * internals of this function will likely cause more warnings. To avoid
678
+ * Spamming too much we disable any warning triggered inside of this
679
+ * stack.
680
+ */
681
+ warningStackCounter++;
682
+ try {
683
+ // If the this binding is unchanged, we defer to the real component.
684
+ // This is important to keep some referential integrity in the
685
+ // internals. E.g. owner equality check.
686
+ var self = this === thisBinding ? this.__realComponentInstance : this;
687
+ return fn.apply(self, arguments);
688
+ } finally {
689
+ warningStackCounter--;
690
+ }
691
+ };
692
+ };
693
+
694
+ var defineMembraneProperty = function(membrane, prototype, key) {
695
+ Object.defineProperty(membrane, key, {
696
+
697
+ configurable: false,
698
+ enumerable: true,
699
+
700
+ get: function() {
701
+ if (this === membrane) {
702
+ // We're allowed to access the prototype directly.
703
+ return prototype[key];
704
+ }
705
+ issueMembraneWarning(this, key);
706
+
707
+ var realValue = this.__realComponentInstance[key];
708
+ // If the real value is a function, we need to provide a wrapper that
709
+ // disables nested warnings. The properties type and constructors are
710
+ // expected to the be constructors and therefore is often use with an
711
+ // equality check and we shouldn't try to rebind those.
712
+ if (typeof realValue === 'function' &&
713
+ key !== 'type' &&
714
+ key !== 'constructor') {
715
+ return wrapInMembraneFunction(realValue, this);
716
+ }
717
+ return realValue;
718
+ },
719
+
720
+ set: function(value) {
721
+ if (this === membrane) {
722
+ // We're allowed to set a value on the prototype directly.
723
+ prototype[key] = value;
724
+ return;
725
+ }
726
+ issueMembraneWarning(this, key);
727
+ this.__realComponentInstance[key] = value;
728
+ }
729
+
730
+ });
731
+ };
732
+
733
+ /**
734
+ * Creates a membrane prototype which wraps the original prototype. If any
735
+ * property is accessed in an unmounted state, a warning is issued.
736
+ *
737
+ * @param {object} prototype Original prototype.
738
+ * @return {object} The membrane prototype.
739
+ * @private
740
+ */
741
+ var createMountWarningMembrane = function(prototype) {
742
+ var membrane = {};
743
+ var key;
744
+ for (key in prototype) {
745
+ defineMembraneProperty(membrane, prototype, key);
746
+ }
747
+ // These are properties that goes into the instance but not the prototype.
748
+ // We can create the membrane on the prototype even though this will
749
+ // result in a faulty hasOwnProperty check it's better perf.
750
+ for (key in componentInstanceProperties) {
751
+ if (componentInstanceProperties.hasOwnProperty(key) &&
752
+ !(key in prototype)) {
753
+ defineMembraneProperty(membrane, prototype, key);
754
+ }
755
+ }
756
+ return membrane;
757
+ };
758
+
759
+ /**
760
+ * Creates a membrane constructor which wraps the component that gets mounted.
761
+ *
762
+ * @param {function} constructor Original constructor.
763
+ * @return {function} The membrane constructor.
764
+ * @private
765
+ */
766
+ var createDescriptorProxy = function(constructor) {
767
+ try {
768
+ var ProxyConstructor = function() {
769
+ this.__realComponentInstance = new constructor();
770
+
771
+ // We can only safely pass through known instance variables. Unknown
772
+ // expandos are not safe. Use the real mounted instance to avoid this
773
+ // problem if it blows something up.
774
+ Object.freeze(this);
775
+ };
776
+
777
+ ProxyConstructor.prototype = createMountWarningMembrane(
778
+ constructor.prototype
779
+ );
780
+
781
+ return ProxyConstructor;
782
+ } catch(x) {
783
+ // In IE8 define property will fail on non-DOM objects. If anything in
784
+ // the membrane creation fails, we'll bail out and just use the plain
785
+ // constructor without warnings.
786
+ return constructor;
787
+ }
788
+ };
789
+
790
+ }
791
+
454
792
  /**
455
793
  * `ReactCompositeComponent` maintains an auxiliary life cycle state in
456
794
  * `this._compositeLifeCycleState` (which can be null).
@@ -516,11 +854,34 @@ var ReactCompositeComponentMixin = {
516
854
  construct: function(initialProps, children) {
517
855
  // Children can be either an array or more than one argument
518
856
  ReactComponent.Mixin.construct.apply(this, arguments);
857
+ ReactOwner.Mixin.construct.apply(this, arguments);
858
+
519
859
  this.state = null;
520
860
  this._pendingState = null;
861
+
862
+ this.context = null;
863
+ this._currentContext = ReactContext.current;
864
+ this._pendingContext = null;
865
+
866
+ // The descriptor that was used to instantiate this component. Will be
867
+ // set by the instantiator instead of the constructor since this
868
+ // constructor is currently used by both instances and descriptors.
869
+ this._descriptor = null;
870
+
521
871
  this._compositeLifeCycleState = null;
522
872
  },
523
873
 
874
+ /**
875
+ * Components in the intermediate state now has cyclic references. To avoid
876
+ * breaking JSON serialization we expose a custom JSON format.
877
+ * @return {object} JSON compatible representation.
878
+ * @internal
879
+ * @final
880
+ */
881
+ toJSON: function() {
882
+ return { type: this.type, props: this.props };
883
+ },
884
+
524
885
  /**
525
886
  * Checks whether or not this composite component is mounted.
526
887
  * @return {boolean} True if mounted, false otherwise.
@@ -536,7 +897,7 @@ var ReactCompositeComponentMixin = {
536
897
  * Initializes the component, renders markup, and registers event listeners.
537
898
  *
538
899
  * @param {string} rootID DOM ID of the root node.
539
- * @param {ReactReconcileTransaction} transaction
900
+ * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
540
901
  * @param {number} mountDepth number of components in the owner hierarchy
541
902
  * @return {?string} Rendered markup to be inserted into the DOM.
542
903
  * @final
@@ -554,14 +915,21 @@ var ReactCompositeComponentMixin = {
554
915
  );
555
916
  this._compositeLifeCycleState = CompositeLifeCycle.MOUNTING;
556
917
 
918
+ this.context = this._processContext(this._currentContext);
557
919
  this._defaultProps = this.getDefaultProps ? this.getDefaultProps() : null;
558
- this._processProps(this.props);
920
+ this.props = this._processProps(this.props);
559
921
 
560
922
  if (this.__reactAutoBindMap) {
561
923
  this._bindAutoBindMethods();
562
924
  }
563
925
 
564
926
  this.state = this.getInitialState ? this.getInitialState() : null;
927
+ ("production" !== process.env.NODE_ENV ? invariant(
928
+ typeof this.state === 'object' && !Array.isArray(this.state),
929
+ '%s.getInitialState(): must return an object or null',
930
+ this.constructor.displayName || 'ReactCompositeComponent'
931
+ ) : invariant(typeof this.state === 'object' && !Array.isArray(this.state)));
932
+
565
933
  this._pendingState = null;
566
934
  this._pendingForceUpdate = false;
567
935
 
@@ -575,7 +943,9 @@ var ReactCompositeComponentMixin = {
575
943
  }
576
944
  }
577
945
 
578
- this._renderedComponent = this._renderValidatedComponent();
946
+ this._renderedComponent = instantiateReactComponent(
947
+ this._renderValidatedComponent()
948
+ );
579
949
 
580
950
  // Done with mounting, `setState` will now trigger UI changes.
581
951
  this._compositeLifeCycleState = null;
@@ -606,13 +976,10 @@ var ReactCompositeComponentMixin = {
606
976
 
607
977
  this._defaultProps = null;
608
978
 
609
- ReactComponent.Mixin.unmountComponent.call(this);
610
979
  this._renderedComponent.unmountComponent();
611
980
  this._renderedComponent = null;
612
981
 
613
- if (this.refs) {
614
- this.refs = null;
615
- }
982
+ ReactComponent.Mixin.unmountComponent.call(this);
616
983
 
617
984
  // Some existing components rely on this.props even after they've been
618
985
  // destroyed (in event handlers).
@@ -638,6 +1005,17 @@ var ReactCompositeComponentMixin = {
638
1005
  * @protected
639
1006
  */
640
1007
  setState: function(partialState, callback) {
1008
+ ("production" !== process.env.NODE_ENV ? invariant(
1009
+ typeof partialState === 'object' || partialState == null,
1010
+ 'setState(...): takes an object of state variables to update.'
1011
+ ) : invariant(typeof partialState === 'object' || partialState == null));
1012
+ if ("production" !== process.env.NODE_ENV) {
1013
+ ("production" !== process.env.NODE_ENV ? warning(
1014
+ partialState != null,
1015
+ 'setState(...): You passed an undefined or null state object; ' +
1016
+ 'instead, use forceUpdate().'
1017
+ ) : null);
1018
+ }
641
1019
  // Merge with `_pendingState` if it exists, otherwise with existing state.
642
1020
  this.replaceState(
643
1021
  merge(this._pendingState || this.state, partialState),
@@ -663,29 +1041,107 @@ var ReactCompositeComponentMixin = {
663
1041
  ReactUpdates.enqueueUpdate(this, callback);
664
1042
  },
665
1043
 
1044
+ /**
1045
+ * Filters the context object to only contain keys specified in
1046
+ * `contextTypes`, and asserts that they are valid.
1047
+ *
1048
+ * @param {object} context
1049
+ * @return {?object}
1050
+ * @private
1051
+ */
1052
+ _processContext: function(context) {
1053
+ var maskedContext = null;
1054
+ var contextTypes = this.constructor.contextTypes;
1055
+ if (contextTypes) {
1056
+ maskedContext = {};
1057
+ for (var contextName in contextTypes) {
1058
+ maskedContext[contextName] = context[contextName];
1059
+ }
1060
+ if ("production" !== process.env.NODE_ENV) {
1061
+ this._checkPropTypes(
1062
+ contextTypes,
1063
+ maskedContext,
1064
+ ReactPropTypeLocations.context
1065
+ );
1066
+ }
1067
+ }
1068
+ return maskedContext;
1069
+ },
1070
+
1071
+ /**
1072
+ * @param {object} currentContext
1073
+ * @return {object}
1074
+ * @private
1075
+ */
1076
+ _processChildContext: function(currentContext) {
1077
+ var childContext = this.getChildContext && this.getChildContext();
1078
+ var displayName = this.constructor.displayName || 'ReactCompositeComponent';
1079
+ if (childContext) {
1080
+ ("production" !== process.env.NODE_ENV ? invariant(
1081
+ typeof this.constructor.childContextTypes === 'object',
1082
+ '%s.getChildContext(): childContextTypes must be defined in order to ' +
1083
+ 'use getChildContext().',
1084
+ displayName
1085
+ ) : invariant(typeof this.constructor.childContextTypes === 'object'));
1086
+ if ("production" !== process.env.NODE_ENV) {
1087
+ this._checkPropTypes(
1088
+ this.constructor.childContextTypes,
1089
+ childContext,
1090
+ ReactPropTypeLocations.childContext
1091
+ );
1092
+ }
1093
+ for (var name in childContext) {
1094
+ ("production" !== process.env.NODE_ENV ? invariant(
1095
+ name in this.constructor.childContextTypes,
1096
+ '%s.getChildContext(): key "%s" is not defined in childContextTypes.',
1097
+ displayName,
1098
+ name
1099
+ ) : invariant(name in this.constructor.childContextTypes));
1100
+ }
1101
+ return merge(currentContext, childContext);
1102
+ }
1103
+ return currentContext;
1104
+ },
1105
+
666
1106
  /**
667
1107
  * Processes props by setting default values for unspecified props and
668
- * asserting that the props are valid.
1108
+ * asserting that the props are valid. Does not mutate its argument; returns
1109
+ * a new props object with defaults merged in.
669
1110
  *
670
- * @param {object} props
1111
+ * @param {object} newProps
1112
+ * @return {object}
671
1113
  * @private
672
1114
  */
673
- _processProps: function(props) {
674
- var propName;
1115
+ _processProps: function(newProps) {
1116
+ var props = merge(newProps);
675
1117
  var defaultProps = this._defaultProps;
676
- for (propName in defaultProps) {
677
- if (!(propName in props)) {
1118
+ for (var propName in defaultProps) {
1119
+ if (typeof props[propName] === 'undefined') {
678
1120
  props[propName] = defaultProps[propName];
679
1121
  }
680
1122
  }
681
- var propTypes = this.constructor.propTypes;
682
- if (propTypes) {
683
- var componentName = this.constructor.displayName;
684
- for (propName in propTypes) {
685
- var checkProp = propTypes[propName];
686
- if (checkProp) {
687
- checkProp(props, propName, componentName);
688
- }
1123
+ if ("production" !== process.env.NODE_ENV) {
1124
+ var propTypes = this.constructor.propTypes;
1125
+ if (propTypes) {
1126
+ this._checkPropTypes(propTypes, props, ReactPropTypeLocations.prop);
1127
+ }
1128
+ }
1129
+ return props;
1130
+ },
1131
+
1132
+ /**
1133
+ * Assert that the props are valid
1134
+ *
1135
+ * @param {object} propTypes Map of prop name to a ReactPropType
1136
+ * @param {object} props
1137
+ * @param {string} location e.g. "prop", "context", "child context"
1138
+ * @private
1139
+ */
1140
+ _checkPropTypes: function(propTypes, props, location) {
1141
+ var componentName = this.constructor.displayName;
1142
+ for (var propName in propTypes) {
1143
+ if (propTypes.hasOwnProperty(propName)) {
1144
+ propTypes[propName](props, propName, componentName, location);
689
1145
  }
690
1146
  }
691
1147
  },
@@ -711,41 +1167,63 @@ var ReactCompositeComponentMixin = {
711
1167
  _performUpdateIfNecessary: function(transaction) {
712
1168
  if (this._pendingProps == null &&
713
1169
  this._pendingState == null &&
1170
+ this._pendingContext == null &&
714
1171
  !this._pendingForceUpdate) {
715
1172
  return;
716
1173
  }
717
1174
 
1175
+ var nextFullContext = this._pendingContext || this._currentContext;
1176
+ var nextContext = this._processContext(nextFullContext);
1177
+ this._pendingContext = null;
1178
+
718
1179
  var nextProps = this.props;
719
1180
  if (this._pendingProps != null) {
720
- nextProps = this._pendingProps;
721
- this._processProps(nextProps);
1181
+ nextProps = this._processProps(this._pendingProps);
722
1182
  this._pendingProps = null;
723
1183
 
724
1184
  this._compositeLifeCycleState = CompositeLifeCycle.RECEIVING_PROPS;
725
1185
  if (this.componentWillReceiveProps) {
726
- this.componentWillReceiveProps(nextProps, transaction);
1186
+ this.componentWillReceiveProps(nextProps, nextContext);
727
1187
  }
728
1188
  }
729
1189
 
730
1190
  this._compositeLifeCycleState = CompositeLifeCycle.RECEIVING_STATE;
731
1191
 
1192
+ // Unlike props, state, and context, we specifically don't want to set
1193
+ // _pendingOwner to null here because it's possible for a component to have
1194
+ // a null owner, so we instead make `this._owner === this._pendingOwner`
1195
+ // mean that there's no owner change pending.
1196
+ var nextOwner = this._pendingOwner;
1197
+
732
1198
  var nextState = this._pendingState || this.state;
733
1199
  this._pendingState = null;
734
1200
 
735
- if (this._pendingForceUpdate ||
736
- !this.shouldComponentUpdate ||
737
- this.shouldComponentUpdate(nextProps, nextState)) {
738
- this._pendingForceUpdate = false;
739
- // Will set `this.props` and `this.state`.
740
- this._performComponentUpdate(nextProps, nextState, transaction);
741
- } else {
742
- // If it's determined that a component should not update, we still want
743
- // to set props and state.
744
- this.props = nextProps;
745
- this.state = nextState;
1201
+ try {
1202
+ if (this._pendingForceUpdate ||
1203
+ !this.shouldComponentUpdate ||
1204
+ this.shouldComponentUpdate(nextProps, nextState, nextContext)) {
1205
+ this._pendingForceUpdate = false;
1206
+ // Will set `this.props`, `this.state` and `this.context`.
1207
+ this._performComponentUpdate(
1208
+ nextProps,
1209
+ nextOwner,
1210
+ nextState,
1211
+ nextFullContext,
1212
+ nextContext,
1213
+ transaction
1214
+ );
1215
+ } else {
1216
+ // If it's determined that a component should not update, we still want
1217
+ // to set props and state.
1218
+ this.props = nextProps;
1219
+ this._owner = nextOwner;
1220
+ this.state = nextState;
1221
+ this._currentContext = nextFullContext;
1222
+ this.context = nextContext;
1223
+ }
1224
+ } finally {
1225
+ this._compositeLifeCycleState = null;
746
1226
  }
747
-
748
- this._compositeLifeCycleState = null;
749
1227
  },
750
1228
 
751
1229
  /**
@@ -753,31 +1231,71 @@ var ReactCompositeComponentMixin = {
753
1231
  * performs update.
754
1232
  *
755
1233
  * @param {object} nextProps Next object to set as properties.
1234
+ * @param {?ReactComponent} nextOwner Next component to set as owner
756
1235
  * @param {?object} nextState Next object to set as state.
1236
+ * @param {?object} nextFullContext Next object to set as _currentContext.
1237
+ * @param {?object} nextContext Next object to set as context.
757
1238
  * @param {ReactReconcileTransaction} transaction
758
1239
  * @private
759
1240
  */
760
- _performComponentUpdate: function(nextProps, nextState, transaction) {
1241
+ _performComponentUpdate: function(
1242
+ nextProps,
1243
+ nextOwner,
1244
+ nextState,
1245
+ nextFullContext,
1246
+ nextContext,
1247
+ transaction
1248
+ ) {
761
1249
  var prevProps = this.props;
1250
+ var prevOwner = this._owner;
762
1251
  var prevState = this.state;
1252
+ var prevContext = this.context;
763
1253
 
764
1254
  if (this.componentWillUpdate) {
765
- this.componentWillUpdate(nextProps, nextState, transaction);
1255
+ this.componentWillUpdate(nextProps, nextState, nextContext);
766
1256
  }
767
1257
 
768
1258
  this.props = nextProps;
1259
+ this._owner = nextOwner;
769
1260
  this.state = nextState;
770
-
771
- this.updateComponent(transaction, prevProps, prevState);
1261
+ this._currentContext = nextFullContext;
1262
+ this.context = nextContext;
1263
+
1264
+ this.updateComponent(
1265
+ transaction,
1266
+ prevProps,
1267
+ prevOwner,
1268
+ prevState,
1269
+ prevContext
1270
+ );
772
1271
 
773
1272
  if (this.componentDidUpdate) {
774
1273
  transaction.getReactMountReady().enqueue(
775
1274
  this,
776
- this.componentDidUpdate.bind(this, prevProps, prevState)
1275
+ this.componentDidUpdate.bind(this, prevProps, prevState, prevContext)
777
1276
  );
778
1277
  }
779
1278
  },
780
1279
 
1280
+ receiveComponent: function(nextComponent, transaction) {
1281
+ if (nextComponent === this._descriptor) {
1282
+ // Since props and context are immutable after the component is
1283
+ // mounted, we can do a cheap identity compare here to determine
1284
+ // if this is a superfluous reconcile.
1285
+ return;
1286
+ }
1287
+
1288
+ // Update the descriptor that was last used by this component instance
1289
+ this._descriptor = nextComponent;
1290
+
1291
+ this._pendingContext = nextComponent._currentContext;
1292
+ ReactComponent.Mixin.receiveComponent.call(
1293
+ this,
1294
+ nextComponent,
1295
+ transaction
1296
+ );
1297
+ },
1298
+
781
1299
  /**
782
1300
  * Updates the component's currently mounted DOM representation.
783
1301
  *
@@ -786,32 +1304,41 @@ var ReactCompositeComponentMixin = {
786
1304
  *
787
1305
  * @param {ReactReconcileTransaction} transaction
788
1306
  * @param {object} prevProps
1307
+ * @param {?ReactComponent} prevOwner
789
1308
  * @param {?object} prevState
1309
+ * @param {?object} prevContext
790
1310
  * @internal
791
1311
  * @overridable
792
1312
  */
793
1313
  updateComponent: ReactPerf.measure(
794
1314
  'ReactCompositeComponent',
795
1315
  'updateComponent',
796
- function(transaction, prevProps, prevState) {
797
- ReactComponent.Mixin.updateComponent.call(this, transaction, prevProps);
798
- var currentComponent = this._renderedComponent;
1316
+ function(transaction, prevProps, prevOwner, prevState, prevContext) {
1317
+ ReactComponent.Mixin.updateComponent.call(
1318
+ this,
1319
+ transaction,
1320
+ prevProps,
1321
+ prevOwner
1322
+ );
1323
+
1324
+
1325
+ var prevComponentInstance = this._renderedComponent;
799
1326
  var nextComponent = this._renderValidatedComponent();
800
- if (currentComponent.constructor === nextComponent.constructor) {
801
- currentComponent.receiveComponent(nextComponent, transaction);
1327
+ if (shouldUpdateReactComponent(prevComponentInstance, nextComponent)) {
1328
+ prevComponentInstance.receiveComponent(nextComponent, transaction);
802
1329
  } else {
803
1330
  // These two IDs are actually the same! But nothing should rely on that.
804
1331
  var thisID = this._rootNodeID;
805
- var currentComponentID = currentComponent._rootNodeID;
806
- currentComponent.unmountComponent();
807
- this._renderedComponent = nextComponent;
808
- var nextMarkup = nextComponent.mountComponent(
1332
+ var prevComponentID = prevComponentInstance._rootNodeID;
1333
+ prevComponentInstance.unmountComponent();
1334
+ this._renderedComponent = instantiateReactComponent(nextComponent);
1335
+ var nextMarkup = this._renderedComponent.mountComponent(
809
1336
  thisID,
810
1337
  transaction,
811
1338
  this._mountDepth + 1
812
1339
  );
813
- ReactComponent.DOMIDOperations.dangerouslyReplaceNodeWithMarkupByID(
814
- currentComponentID,
1340
+ ReactComponent.BackendIDOperations.dangerouslyReplaceNodeWithMarkupByID(
1341
+ prevComponentID,
815
1342
  nextMarkup
816
1343
  );
817
1344
  }
@@ -855,25 +1382,29 @@ var ReactCompositeComponentMixin = {
855
1382
  /**
856
1383
  * @private
857
1384
  */
858
- _renderValidatedComponent: function() {
859
- var renderedComponent;
860
- ReactCurrentOwner.current = this;
861
- try {
862
- renderedComponent = this.render();
863
- } catch (error) {
864
- // IE8 requires `catch` in order to use `finally`.
865
- throw error;
866
- } finally {
867
- ReactCurrentOwner.current = null;
1385
+ _renderValidatedComponent: ReactPerf.measure(
1386
+ 'ReactCompositeComponent',
1387
+ '_renderValidatedComponent',
1388
+ function() {
1389
+ var renderedComponent;
1390
+ var previousContext = ReactContext.current;
1391
+ ReactContext.current = this._processChildContext(this._currentContext);
1392
+ ReactCurrentOwner.current = this;
1393
+ try {
1394
+ renderedComponent = this.render();
1395
+ } finally {
1396
+ ReactContext.current = previousContext;
1397
+ ReactCurrentOwner.current = null;
1398
+ }
1399
+ ("production" !== process.env.NODE_ENV ? invariant(
1400
+ ReactComponent.isValidComponent(renderedComponent),
1401
+ '%s.render(): A valid ReactComponent must be returned. You may have ' +
1402
+ 'returned null, undefined, an array, or some other invalid object.',
1403
+ this.constructor.displayName || 'ReactCompositeComponent'
1404
+ ) : invariant(ReactComponent.isValidComponent(renderedComponent)));
1405
+ return renderedComponent;
868
1406
  }
869
- ("production" !== process.env.NODE_ENV ? invariant(
870
- ReactComponent.isValidComponent(renderedComponent),
871
- '%s.render(): A valid ReactComponent must be returned. You may have ' +
872
- 'returned null, undefined, an array, or some other invalid object.',
873
- this.constructor.displayName || 'ReactCompositeComponent'
874
- ) : invariant(ReactComponent.isValidComponent(renderedComponent)));
875
- return renderedComponent;
876
- },
1407
+ ),
877
1408
 
878
1409
  /**
879
1410
  * @private
@@ -908,16 +1439,18 @@ var ReactCompositeComponentMixin = {
908
1439
  boundMethod.__reactBoundArguments = null;
909
1440
  var componentName = component.constructor.displayName;
910
1441
  var _bind = boundMethod.bind;
911
- boundMethod.bind = function(newThis) {
1442
+ boundMethod.bind = function(newThis ) {var args=Array.prototype.slice.call(arguments,1);
912
1443
  // User is trying to bind() an autobound method; we effectively will
913
1444
  // ignore the value of "this" that the user is trying to use, so
914
1445
  // let's warn.
915
1446
  if (newThis !== component && newThis !== null) {
1447
+ monitorCodeUse('react_bind_warning', { component: componentName });
916
1448
  console.warn(
917
1449
  'bind(): React component methods may only be bound to the ' +
918
1450
  'component instance. See ' + componentName
919
1451
  );
920
- } else if (arguments.length === 1) {
1452
+ } else if (!args.length) {
1453
+ monitorCodeUse('react_bind_warning', { component: componentName });
921
1454
  console.warn(
922
1455
  'bind(): You are binding a component method to the component. ' +
923
1456
  'React does this for you automatically in a high-performance ' +
@@ -928,8 +1461,7 @@ var ReactCompositeComponentMixin = {
928
1461
  var reboundMethod = _bind.apply(boundMethod, arguments);
929
1462
  reboundMethod.__reactBoundContext = component;
930
1463
  reboundMethod.__reactBoundMethod = method;
931
- reboundMethod.__reactBoundArguments =
932
- Array.prototype.slice.call(arguments, 1);
1464
+ reboundMethod.__reactBoundArguments = args;
933
1465
  return reboundMethod;
934
1466
  };
935
1467
  }
@@ -943,6 +1475,18 @@ mixInto(ReactCompositeComponentBase, ReactOwner.Mixin);
943
1475
  mixInto(ReactCompositeComponentBase, ReactPropTransferer.Mixin);
944
1476
  mixInto(ReactCompositeComponentBase, ReactCompositeComponentMixin);
945
1477
 
1478
+ /**
1479
+ * Checks if a value is a valid component constructor.
1480
+ *
1481
+ * @param {*}
1482
+ * @return {boolean}
1483
+ * @public
1484
+ */
1485
+ function isValidClass(componentClass) {
1486
+ return componentClass instanceof Function &&
1487
+ 'componentConstructor' in componentClass &&
1488
+ componentClass.componentConstructor instanceof Function;
1489
+ }
946
1490
  /**
947
1491
  * Module for creating composite components.
948
1492
  *
@@ -968,7 +1512,23 @@ var ReactCompositeComponent = {
968
1512
  var Constructor = function() {};
969
1513
  Constructor.prototype = new ReactCompositeComponentBase();
970
1514
  Constructor.prototype.constructor = Constructor;
971
- mixSpecIntoComponent(Constructor, spec);
1515
+
1516
+ var DescriptorConstructor = Constructor;
1517
+
1518
+ var ConvenienceConstructor = function(props, children) {
1519
+ var descriptor = new DescriptorConstructor();
1520
+ descriptor.construct.apply(descriptor, arguments);
1521
+ return descriptor;
1522
+ };
1523
+ ConvenienceConstructor.componentConstructor = Constructor;
1524
+ Constructor.ConvenienceConstructor = ConvenienceConstructor;
1525
+ ConvenienceConstructor.originalSpec = spec;
1526
+
1527
+ injectedMixins.forEach(
1528
+ mixSpecIntoComponent.bind(null, ConvenienceConstructor)
1529
+ );
1530
+
1531
+ mixSpecIntoComponent(ConvenienceConstructor, spec);
972
1532
 
973
1533
  ("production" !== process.env.NODE_ENV ? invariant(
974
1534
  Constructor.prototype.render,
@@ -977,6 +1537,10 @@ var ReactCompositeComponent = {
977
1537
 
978
1538
  if ("production" !== process.env.NODE_ENV) {
979
1539
  if (Constructor.prototype.componentShouldUpdate) {
1540
+ monitorCodeUse(
1541
+ 'react_component_should_update_warning',
1542
+ { component: spec.displayName }
1543
+ );
980
1544
  console.warn(
981
1545
  (spec.displayName || 'A component') + ' has a method called ' +
982
1546
  'componentShouldUpdate(). Did you mean shouldComponentUpdate()? ' +
@@ -986,6 +1550,14 @@ var ReactCompositeComponent = {
986
1550
  }
987
1551
  }
988
1552
 
1553
+ // Expose the convience constructor on the prototype so that it can be
1554
+ // easily accessed on descriptors. E.g. <Foo />.type === Foo.type and for
1555
+ // static methods like <Foo />.type.staticMethod();
1556
+ // This should not be named constructor since this may not be the function
1557
+ // that created the descriptor, and it may not even be a constructor.
1558
+ ConvenienceConstructor.type = Constructor;
1559
+ Constructor.prototype.type = Constructor;
1560
+
989
1561
  // Reduce time spent doing lookups by setting these on the prototype.
990
1562
  for (var methodName in ReactCompositeComponentInterface) {
991
1563
  if (!Constructor.prototype[methodName]) {
@@ -993,27 +1565,22 @@ var ReactCompositeComponent = {
993
1565
  }
994
1566
  }
995
1567
 
996
- var ConvenienceConstructor = function(props, children) {
997
- var instance = new Constructor();
998
- instance.construct.apply(instance, arguments);
999
- return instance;
1000
- };
1001
- ConvenienceConstructor.componentConstructor = Constructor;
1002
- ConvenienceConstructor.originalSpec = spec;
1568
+ if ("production" !== process.env.NODE_ENV) {
1569
+ // In DEV the convenience constructor generates a proxy to another
1570
+ // instance around it to warn about access to properties on the
1571
+ // descriptor.
1572
+ DescriptorConstructor = createDescriptorProxy(Constructor);
1573
+ }
1574
+
1003
1575
  return ConvenienceConstructor;
1004
1576
  },
1005
1577
 
1006
- /**
1007
- * Checks if a value is a valid component constructor.
1008
- *
1009
- * @param {*}
1010
- * @return {boolean}
1011
- * @public
1012
- */
1013
- isValidClass: function(componentClass) {
1014
- return componentClass instanceof Function &&
1015
- 'componentConstructor' in componentClass &&
1016
- componentClass.componentConstructor instanceof Function;
1578
+ isValidClass: isValidClass,
1579
+
1580
+ injection: {
1581
+ injectMixin: function(mixin) {
1582
+ injectedMixins.push(mixin);
1583
+ }
1017
1584
  }
1018
1585
  };
1019
1586