react 0.12.2 → 0.13.0-beta.2

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 (184) hide show
  1. package/dist/JSXTransformer.js +986 -511
  2. package/dist/react-with-addons.js +6076 -4560
  3. package/dist/react-with-addons.min.js +6 -7
  4. package/dist/react.js +5386 -4170
  5. package/dist/react.min.js +6 -7
  6. package/lib/AutoFocusMixin.js +2 -2
  7. package/lib/BeforeInputEventPlugin.js +388 -115
  8. package/lib/CSSCore.js +1 -1
  9. package/lib/CSSProperty.js +2 -2
  10. package/lib/CSSPropertyOperations.js +58 -11
  11. package/lib/CallbackQueue.js +3 -3
  12. package/lib/ChangeEventPlugin.js +4 -4
  13. package/lib/ClientReactRootIndex.js +2 -2
  14. package/lib/DOMChildrenOperations.js +10 -47
  15. package/lib/DOMProperty.js +2 -2
  16. package/lib/DOMPropertyOperations.js +11 -16
  17. package/lib/Danger.js +8 -7
  18. package/lib/DefaultEventPluginOrder.js +3 -4
  19. package/lib/EnterLeaveEventPlugin.js +2 -2
  20. package/lib/EventConstants.js +2 -2
  21. package/lib/EventListener.js +1 -1
  22. package/lib/EventPluginHub.js +10 -8
  23. package/lib/EventPluginRegistry.js +2 -2
  24. package/lib/EventPluginUtils.js +4 -4
  25. package/lib/EventPropagators.js +2 -2
  26. package/lib/ExecutionEnvironment.js +3 -4
  27. package/lib/FallbackCompositionState.js +89 -0
  28. package/lib/HTMLDOMPropertyConfig.js +23 -10
  29. package/lib/LinkedStateMixin.js +2 -2
  30. package/lib/LinkedValueUtils.js +4 -4
  31. package/lib/LocalEventTrapMixin.js +10 -3
  32. package/lib/MobileSafariClickEventPlugin.js +2 -2
  33. package/lib/Object.assign.js +4 -2
  34. package/lib/PooledClass.js +2 -2
  35. package/lib/React.js +19 -58
  36. package/lib/ReactBrowserComponentMixin.js +4 -14
  37. package/lib/ReactBrowserEventEmitter.js +6 -8
  38. package/lib/ReactCSSTransitionGroup.js +5 -2
  39. package/lib/ReactCSSTransitionGroupChild.js +20 -7
  40. package/lib/ReactChildReconciler.js +125 -0
  41. package/lib/ReactChildren.js +13 -10
  42. package/lib/ReactClass.js +918 -0
  43. package/lib/ReactComponent.js +98 -406
  44. package/lib/ReactComponentBrowserEnvironment.js +11 -84
  45. package/lib/ReactComponentEnvironment.js +57 -0
  46. package/lib/ReactComponentWithPureRenderMixin.js +2 -2
  47. package/lib/ReactCompositeComponent.js +574 -1140
  48. package/lib/ReactContext.js +17 -3
  49. package/lib/ReactCurrentOwner.js +2 -2
  50. package/lib/ReactDOM.js +4 -9
  51. package/lib/ReactDOMButton.js +6 -7
  52. package/lib/ReactDOMComponent.js +123 -105
  53. package/lib/ReactDOMForm.js +6 -7
  54. package/lib/ReactDOMIDOperations.js +59 -77
  55. package/lib/ReactDOMIframe.js +43 -0
  56. package/lib/ReactDOMImg.js +5 -7
  57. package/lib/ReactDOMInput.js +6 -7
  58. package/lib/ReactDOMOption.js +6 -7
  59. package/lib/ReactDOMSelect.js +58 -66
  60. package/lib/ReactDOMSelection.js +7 -3
  61. package/lib/{ReactTextComponent.js → ReactDOMTextComponent.js} +48 -37
  62. package/lib/ReactDOMTextarea.js +6 -7
  63. package/lib/ReactDefaultBatchingStrategy.js +5 -5
  64. package/lib/ReactDefaultInjection.js +39 -9
  65. package/lib/ReactDefaultPerf.js +17 -8
  66. package/lib/ReactDefaultPerfAnalysis.js +2 -2
  67. package/lib/ReactElement.js +23 -15
  68. package/lib/ReactElementValidator.js +206 -89
  69. package/lib/ReactEmptyComponent.js +33 -15
  70. package/lib/ReactErrorUtils.js +1 -1
  71. package/lib/ReactEventEmitterMixin.js +2 -2
  72. package/lib/ReactEventListener.js +4 -5
  73. package/lib/ReactFragment.js +172 -0
  74. package/lib/ReactInjection.js +8 -6
  75. package/lib/ReactInputSelection.js +4 -5
  76. package/lib/ReactInstanceHandles.js +4 -3
  77. package/lib/ReactInstanceMap.js +47 -0
  78. package/lib/ReactLifeCycle.js +35 -0
  79. package/lib/ReactLink.js +2 -2
  80. package/lib/ReactMarkupChecksum.js +2 -2
  81. package/lib/ReactMount.js +264 -71
  82. package/lib/ReactMultiChild.js +50 -48
  83. package/lib/ReactMultiChildUpdateTypes.js +2 -2
  84. package/lib/ReactNativeComponent.js +59 -25
  85. package/lib/ReactOwner.js +5 -49
  86. package/lib/ReactPerf.js +22 -2
  87. package/lib/ReactPropTransferer.js +3 -58
  88. package/lib/ReactPropTypeLocationNames.js +2 -2
  89. package/lib/ReactPropTypeLocations.js +2 -2
  90. package/lib/ReactPropTypes.js +17 -25
  91. package/lib/ReactPutListenerQueue.js +2 -2
  92. package/lib/ReactReconcileTransaction.js +2 -2
  93. package/lib/ReactReconciler.js +121 -0
  94. package/lib/ReactRef.js +69 -0
  95. package/lib/ReactRootIndex.js +2 -2
  96. package/lib/ReactServerRendering.js +6 -4
  97. package/lib/ReactServerRenderingTransaction.js +2 -2
  98. package/lib/ReactStateSetters.js +2 -2
  99. package/lib/ReactTestUtils.js +113 -27
  100. package/lib/ReactTransitionChildMapping.js +8 -4
  101. package/lib/ReactTransitionEvents.js +2 -2
  102. package/lib/ReactTransitionGroup.js +53 -12
  103. package/lib/ReactUpdateQueue.js +295 -0
  104. package/lib/ReactUpdates.js +54 -62
  105. package/lib/ReactWithAddons.js +4 -2
  106. package/lib/SVGDOMPropertyConfig.js +2 -2
  107. package/lib/SelectEventPlugin.js +4 -4
  108. package/lib/ServerReactRootIndex.js +2 -2
  109. package/lib/SimpleEventPlugin.js +4 -4
  110. package/lib/SyntheticClipboardEvent.js +2 -3
  111. package/lib/SyntheticCompositionEvent.js +2 -3
  112. package/lib/SyntheticDragEvent.js +2 -2
  113. package/lib/SyntheticEvent.js +12 -4
  114. package/lib/SyntheticFocusEvent.js +2 -2
  115. package/lib/SyntheticInputEvent.js +2 -3
  116. package/lib/SyntheticKeyboardEvent.js +2 -2
  117. package/lib/SyntheticMouseEvent.js +3 -5
  118. package/lib/SyntheticTouchEvent.js +2 -2
  119. package/lib/SyntheticUIEvent.js +2 -2
  120. package/lib/SyntheticWheelEvent.js +2 -2
  121. package/lib/Transaction.js +4 -4
  122. package/lib/ViewportMetrics.js +3 -6
  123. package/lib/accumulateInto.js +2 -2
  124. package/lib/adler32.js +2 -2
  125. package/lib/camelize.js +1 -1
  126. package/lib/camelizeStyleName.js +1 -1
  127. package/lib/cloneWithProps.js +4 -4
  128. package/lib/containsNode.js +1 -1
  129. package/lib/{createArrayFrom.js → createArrayFromMixed.js} +6 -6
  130. package/lib/createFullPageComponent.js +4 -4
  131. package/lib/createNodesFromMarkup.js +4 -4
  132. package/lib/cx.js +1 -1
  133. package/lib/dangerousStyleValue.js +2 -2
  134. package/lib/emptyFunction.js +1 -1
  135. package/lib/emptyObject.js +1 -1
  136. package/lib/{escapeTextForBrowser.js → escapeTextContentForBrowser.js} +10 -11
  137. package/lib/findDOMNode.js +51 -0
  138. package/lib/flattenChildren.js +12 -23
  139. package/lib/focusNode.js +1 -1
  140. package/lib/forEachAccumulated.js +2 -2
  141. package/lib/getActiveElement.js +1 -1
  142. package/lib/getEventCharCode.js +2 -2
  143. package/lib/getEventKey.js +2 -2
  144. package/lib/getEventModifierState.js +2 -2
  145. package/lib/getEventTarget.js +2 -2
  146. package/lib/getIteratorFn.js +42 -0
  147. package/lib/getMarkupWrap.js +1 -1
  148. package/lib/getNodeForCharacterOffset.js +3 -3
  149. package/lib/getReactRootElementInContainer.js +2 -2
  150. package/lib/getTextContentAccessor.js +2 -2
  151. package/lib/getUnboundedScrollPosition.js +1 -1
  152. package/lib/hyphenate.js +1 -1
  153. package/lib/hyphenateStyleName.js +1 -1
  154. package/lib/instantiateReactComponent.js +90 -68
  155. package/lib/invariant.js +1 -1
  156. package/lib/isEventSupported.js +2 -2
  157. package/lib/isNode.js +4 -5
  158. package/lib/isTextInputElement.js +3 -4
  159. package/lib/isTextNode.js +1 -1
  160. package/lib/joinClasses.js +2 -2
  161. package/lib/keyMirror.js +2 -2
  162. package/lib/keyOf.js +1 -1
  163. package/lib/mapObject.js +1 -1
  164. package/lib/memoizeStringOnly.js +5 -6
  165. package/lib/onlyChild.js +2 -2
  166. package/lib/performance.js +1 -1
  167. package/lib/performanceNow.js +1 -1
  168. package/lib/quoteAttributeValueForBrowser.js +26 -0
  169. package/lib/setInnerHTML.js +13 -2
  170. package/lib/setTextContent.js +40 -0
  171. package/lib/shallowEqual.js +2 -2
  172. package/lib/shouldUpdateReactComponent.js +71 -7
  173. package/lib/toArray.js +2 -2
  174. package/lib/traverseAllChildren.js +114 -56
  175. package/lib/update.js +2 -2
  176. package/lib/warning.js +20 -2
  177. package/package.json +1 -1
  178. package/lib/CompositionEventPlugin.js +0 -257
  179. package/lib/ReactLegacyElement.js +0 -243
  180. package/lib/copyProperties.js +0 -54
  181. package/lib/deprecated.js +0 -47
  182. package/lib/merge.js +0 -34
  183. package/lib/mergeInto.js +0 -24
  184. package/lib/monitorCodeUse.js +0 -30
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Copyright 2013-2014, Facebook, Inc.
2
+ * Copyright 2013-2015, Facebook, Inc.
3
3
  * All rights reserved.
4
4
  *
5
5
  * This source code is licensed under the BSD-style license found in the
@@ -11,31 +11,23 @@
11
11
 
12
12
  /*jslint evil: true */
13
13
 
14
- "use strict";
14
+ 'use strict';
15
15
 
16
16
  var ReactDOMIDOperations = require("./ReactDOMIDOperations");
17
- var ReactMarkupChecksum = require("./ReactMarkupChecksum");
18
17
  var ReactMount = require("./ReactMount");
19
- var ReactPerf = require("./ReactPerf");
20
- var ReactReconcileTransaction = require("./ReactReconcileTransaction");
21
-
22
- var getReactRootElementInContainer = require("./getReactRootElementInContainer");
23
- var invariant = require("./invariant");
24
- var setInnerHTML = require("./setInnerHTML");
25
-
26
-
27
- var ELEMENT_NODE_TYPE = 1;
28
- var DOC_NODE_TYPE = 9;
29
-
30
18
 
31
19
  /**
32
- * Abstracts away all functionality of `ReactComponent` requires knowledge of
33
- * the browser context.
20
+ * Abstracts away all functionality of the reconciler that requires knowledge of
21
+ * the browser context. TODO: These callers should be refactored to avoid the
22
+ * need for this injection.
34
23
  */
35
24
  var ReactComponentBrowserEnvironment = {
36
- ReactReconcileTransaction: ReactReconcileTransaction,
37
25
 
38
- BackendIDOperations: ReactDOMIDOperations,
26
+ processChildrenUpdates:
27
+ ReactDOMIDOperations.dangerouslyProcessChildrenUpdates,
28
+
29
+ replaceNodeWithMarkupByID:
30
+ ReactDOMIDOperations.dangerouslyReplaceNodeWithMarkupByID,
39
31
 
40
32
  /**
41
33
  * If a particular environment requires that some resources be cleaned up,
@@ -46,73 +38,8 @@ var ReactComponentBrowserEnvironment = {
46
38
  */
47
39
  unmountIDFromEnvironment: function(rootNodeID) {
48
40
  ReactMount.purgeID(rootNodeID);
49
- },
50
-
51
- /**
52
- * @param {string} markup Markup string to place into the DOM Element.
53
- * @param {DOMElement} container DOM Element to insert markup into.
54
- * @param {boolean} shouldReuseMarkup Should reuse the existing markup in the
55
- * container if possible.
56
- */
57
- mountImageIntoNode: ReactPerf.measure(
58
- 'ReactComponentBrowserEnvironment',
59
- 'mountImageIntoNode',
60
- function(markup, container, shouldReuseMarkup) {
61
- ("production" !== process.env.NODE_ENV ? invariant(
62
- container && (
63
- container.nodeType === ELEMENT_NODE_TYPE ||
64
- container.nodeType === DOC_NODE_TYPE
65
- ),
66
- 'mountComponentIntoNode(...): Target container is not valid.'
67
- ) : invariant(container && (
68
- container.nodeType === ELEMENT_NODE_TYPE ||
69
- container.nodeType === DOC_NODE_TYPE
70
- )));
71
-
72
- if (shouldReuseMarkup) {
73
- if (ReactMarkupChecksum.canReuseMarkup(
74
- markup,
75
- getReactRootElementInContainer(container))) {
76
- return;
77
- } else {
78
- ("production" !== process.env.NODE_ENV ? invariant(
79
- container.nodeType !== DOC_NODE_TYPE,
80
- 'You\'re trying to render a component to the document using ' +
81
- 'server rendering but the checksum was invalid. This usually ' +
82
- 'means you rendered a different component type or props on ' +
83
- 'the client from the one on the server, or your render() ' +
84
- 'methods are impure. React cannot handle this case due to ' +
85
- 'cross-browser quirks by rendering at the document root. You ' +
86
- 'should look for environment dependent code in your components ' +
87
- 'and ensure the props are the same client and server side.'
88
- ) : invariant(container.nodeType !== DOC_NODE_TYPE));
89
-
90
- if ("production" !== process.env.NODE_ENV) {
91
- console.warn(
92
- 'React attempted to use reuse markup in a container but the ' +
93
- 'checksum was invalid. This generally means that you are ' +
94
- 'using server rendering and the markup generated on the ' +
95
- 'server was not what the client was expecting. React injected ' +
96
- 'new markup to compensate which works but you have lost many ' +
97
- 'of the benefits of server rendering. Instead, figure out ' +
98
- 'why the markup being generated is different on the client ' +
99
- 'or server.'
100
- );
101
- }
102
- }
103
- }
104
-
105
- ("production" !== process.env.NODE_ENV ? invariant(
106
- container.nodeType !== DOC_NODE_TYPE,
107
- 'You\'re trying to render a component to the document but ' +
108
- 'you didn\'t use server rendering. We can\'t do this ' +
109
- 'without using server rendering due to cross-browser quirks. ' +
110
- 'See renderComponentToString() for server rendering.'
111
- ) : invariant(container.nodeType !== DOC_NODE_TYPE));
41
+ }
112
42
 
113
- setInnerHTML(container, markup);
114
- }
115
- )
116
43
  };
117
44
 
118
45
  module.exports = ReactComponentBrowserEnvironment;
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Copyright 2014-2015, Facebook, Inc.
3
+ * All rights reserved.
4
+ *
5
+ * This source code is licensed under the BSD-style license found in the
6
+ * LICENSE file in the root directory of this source tree. An additional grant
7
+ * of patent rights can be found in the PATENTS file in the same directory.
8
+ *
9
+ * @providesModule ReactComponentEnvironment
10
+ */
11
+
12
+ 'use strict';
13
+
14
+ var invariant = require("./invariant");
15
+
16
+ var injected = false;
17
+
18
+ var ReactComponentEnvironment = {
19
+
20
+ /**
21
+ * Optionally injectable environment dependent cleanup hook. (server vs.
22
+ * browser etc). Example: A browser system caches DOM nodes based on component
23
+ * ID and must remove that cache entry when this instance is unmounted.
24
+ */
25
+ unmountIDFromEnvironment: null,
26
+
27
+ /**
28
+ * Optionally injectable hook for swapping out mount images in the middle of
29
+ * the tree.
30
+ */
31
+ replaceNodeWithMarkupByID: null,
32
+
33
+ /**
34
+ * Optionally injectable hook for processing a queue of child updates. Will
35
+ * later move into MultiChildComponents.
36
+ */
37
+ processChildrenUpdates: null,
38
+
39
+ injection: {
40
+ injectEnvironment: function(environment) {
41
+ ("production" !== process.env.NODE_ENV ? invariant(
42
+ !injected,
43
+ 'ReactCompositeComponent: injectEnvironment() can only be called once.'
44
+ ) : invariant(!injected));
45
+ ReactComponentEnvironment.unmountIDFromEnvironment =
46
+ environment.unmountIDFromEnvironment;
47
+ ReactComponentEnvironment.replaceNodeWithMarkupByID =
48
+ environment.replaceNodeWithMarkupByID;
49
+ ReactComponentEnvironment.processChildrenUpdates =
50
+ environment.processChildrenUpdates;
51
+ injected = true;
52
+ }
53
+ }
54
+
55
+ };
56
+
57
+ module.exports = ReactComponentEnvironment;
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Copyright 2013-2014, Facebook, Inc.
2
+ * Copyright 2013-2015, Facebook, Inc.
3
3
  * All rights reserved.
4
4
  *
5
5
  * This source code is licensed under the BSD-style license found in the
@@ -9,7 +9,7 @@
9
9
  * @providesModule ReactComponentWithPureRenderMixin
10
10
  */
11
11
 
12
- "use strict";
12
+ 'use strict';
13
13
 
14
14
  var shallowEqual = require("./shallowEqual");
15
15
 
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Copyright 2013-2014, Facebook, Inc.
2
+ * Copyright 2013-2015, Facebook, Inc.
3
3
  * All rights reserved.
4
4
  *
5
5
  * This source code is licensed under the BSD-style license found in the
@@ -9,707 +9,73 @@
9
9
  * @providesModule ReactCompositeComponent
10
10
  */
11
11
 
12
- "use strict";
12
+ 'use strict';
13
13
 
14
- var ReactComponent = require("./ReactComponent");
14
+ var ReactComponentEnvironment = require("./ReactComponentEnvironment");
15
15
  var ReactContext = require("./ReactContext");
16
16
  var ReactCurrentOwner = require("./ReactCurrentOwner");
17
17
  var ReactElement = require("./ReactElement");
18
18
  var ReactElementValidator = require("./ReactElementValidator");
19
- var ReactEmptyComponent = require("./ReactEmptyComponent");
20
- var ReactErrorUtils = require("./ReactErrorUtils");
21
- var ReactLegacyElement = require("./ReactLegacyElement");
22
- var ReactOwner = require("./ReactOwner");
19
+ var ReactInstanceMap = require("./ReactInstanceMap");
20
+ var ReactLifeCycle = require("./ReactLifeCycle");
21
+ var ReactNativeComponent = require("./ReactNativeComponent");
23
22
  var ReactPerf = require("./ReactPerf");
24
- var ReactPropTransferer = require("./ReactPropTransferer");
25
23
  var ReactPropTypeLocations = require("./ReactPropTypeLocations");
26
24
  var ReactPropTypeLocationNames = require("./ReactPropTypeLocationNames");
25
+ var ReactReconciler = require("./ReactReconciler");
27
26
  var ReactUpdates = require("./ReactUpdates");
28
27
 
29
28
  var assign = require("./Object.assign");
30
- var instantiateReactComponent = require("./instantiateReactComponent");
29
+ var emptyObject = require("./emptyObject");
31
30
  var invariant = require("./invariant");
32
- var keyMirror = require("./keyMirror");
33
- var keyOf = require("./keyOf");
34
- var monitorCodeUse = require("./monitorCodeUse");
35
- var mapObject = require("./mapObject");
36
31
  var shouldUpdateReactComponent = require("./shouldUpdateReactComponent");
37
32
  var warning = require("./warning");
38
33
 
39
- var MIXINS_KEY = keyOf({mixins: null});
40
-
41
- /**
42
- * Policies that describe methods in `ReactCompositeComponentInterface`.
43
- */
44
- var SpecPolicy = keyMirror({
45
- /**
46
- * These methods may be defined only once by the class specification or mixin.
47
- */
48
- DEFINE_ONCE: null,
49
- /**
50
- * These methods may be defined by both the class specification and mixins.
51
- * Subsequent definitions will be chained. These methods must return void.
52
- */
53
- DEFINE_MANY: null,
54
- /**
55
- * These methods are overriding the base ReactCompositeComponent class.
56
- */
57
- OVERRIDE_BASE: null,
58
- /**
59
- * These methods are similar to DEFINE_MANY, except we assume they return
60
- * objects. We try to merge the keys of the return values of all the mixed in
61
- * functions. If there is a key conflict we throw.
62
- */
63
- DEFINE_MANY_MERGED: null
64
- });
65
-
66
-
67
- var injectedMixins = [];
68
-
69
- /**
70
- * Composite components are higher-level components that compose other composite
71
- * or native components.
72
- *
73
- * To create a new type of `ReactCompositeComponent`, pass a specification of
74
- * your new class to `React.createClass`. The only requirement of your class
75
- * specification is that you implement a `render` method.
76
- *
77
- * var MyComponent = React.createClass({
78
- * render: function() {
79
- * return <div>Hello World</div>;
80
- * }
81
- * });
82
- *
83
- * The class specification supports a specific protocol of methods that have
84
- * special meaning (e.g. `render`). See `ReactCompositeComponentInterface` for
85
- * more the comprehensive protocol. Any other properties and methods in the
86
- * class specification will available on the prototype.
87
- *
88
- * @interface ReactCompositeComponentInterface
89
- * @internal
90
- */
91
- var ReactCompositeComponentInterface = {
92
-
93
- /**
94
- * An array of Mixin objects to include when defining your component.
95
- *
96
- * @type {array}
97
- * @optional
98
- */
99
- mixins: SpecPolicy.DEFINE_MANY,
100
-
101
- /**
102
- * An object containing properties and methods that should be defined on
103
- * the component's constructor instead of its prototype (static methods).
104
- *
105
- * @type {object}
106
- * @optional
107
- */
108
- statics: SpecPolicy.DEFINE_MANY,
109
-
110
- /**
111
- * Definition of prop types for this component.
112
- *
113
- * @type {object}
114
- * @optional
115
- */
116
- propTypes: SpecPolicy.DEFINE_MANY,
117
-
118
- /**
119
- * Definition of context types for this component.
120
- *
121
- * @type {object}
122
- * @optional
123
- */
124
- contextTypes: SpecPolicy.DEFINE_MANY,
125
-
126
- /**
127
- * Definition of context types this component sets for its children.
128
- *
129
- * @type {object}
130
- * @optional
131
- */
132
- childContextTypes: SpecPolicy.DEFINE_MANY,
133
-
134
- // ==== Definition methods ====
135
-
136
- /**
137
- * Invoked when the component is mounted. Values in the mapping will be set on
138
- * `this.props` if that prop is not specified (i.e. using an `in` check).
139
- *
140
- * This method is invoked before `getInitialState` and therefore cannot rely
141
- * on `this.state` or use `this.setState`.
142
- *
143
- * @return {object}
144
- * @optional
145
- */
146
- getDefaultProps: SpecPolicy.DEFINE_MANY_MERGED,
147
-
148
- /**
149
- * Invoked once before the component is mounted. The return value will be used
150
- * as the initial value of `this.state`.
151
- *
152
- * getInitialState: function() {
153
- * return {
154
- * isOn: false,
155
- * fooBaz: new BazFoo()
156
- * }
157
- * }
158
- *
159
- * @return {object}
160
- * @optional
161
- */
162
- getInitialState: SpecPolicy.DEFINE_MANY_MERGED,
163
-
164
- /**
165
- * @return {object}
166
- * @optional
167
- */
168
- getChildContext: SpecPolicy.DEFINE_MANY_MERGED,
169
-
170
- /**
171
- * Uses props from `this.props` and state from `this.state` to render the
172
- * structure of the component.
173
- *
174
- * No guarantees are made about when or how often this method is invoked, so
175
- * it must not have side effects.
176
- *
177
- * render: function() {
178
- * var name = this.props.name;
179
- * return <div>Hello, {name}!</div>;
180
- * }
181
- *
182
- * @return {ReactComponent}
183
- * @nosideeffects
184
- * @required
185
- */
186
- render: SpecPolicy.DEFINE_ONCE,
187
-
188
-
189
-
190
- // ==== Delegate methods ====
191
-
192
- /**
193
- * Invoked when the component is initially created and about to be mounted.
194
- * This may have side effects, but any external subscriptions or data created
195
- * by this method must be cleaned up in `componentWillUnmount`.
196
- *
197
- * @optional
198
- */
199
- componentWillMount: SpecPolicy.DEFINE_MANY,
200
-
201
- /**
202
- * Invoked when the component has been mounted and has a DOM representation.
203
- * However, there is no guarantee that the DOM node is in the document.
204
- *
205
- * Use this as an opportunity to operate on the DOM when the component has
206
- * been mounted (initialized and rendered) for the first time.
207
- *
208
- * @param {DOMElement} rootNode DOM element representing the component.
209
- * @optional
210
- */
211
- componentDidMount: SpecPolicy.DEFINE_MANY,
212
-
213
- /**
214
- * Invoked before the component receives new props.
215
- *
216
- * Use this as an opportunity to react to a prop transition by updating the
217
- * state using `this.setState`. Current props are accessed via `this.props`.
218
- *
219
- * componentWillReceiveProps: function(nextProps, nextContext) {
220
- * this.setState({
221
- * likesIncreasing: nextProps.likeCount > this.props.likeCount
222
- * });
223
- * }
224
- *
225
- * NOTE: There is no equivalent `componentWillReceiveState`. An incoming prop
226
- * transition may cause a state change, but the opposite is not true. If you
227
- * need it, you are probably looking for `componentWillUpdate`.
228
- *
229
- * @param {object} nextProps
230
- * @optional
231
- */
232
- componentWillReceiveProps: SpecPolicy.DEFINE_MANY,
233
-
234
- /**
235
- * Invoked while deciding if the component should be updated as a result of
236
- * receiving new props, state and/or context.
237
- *
238
- * Use this as an opportunity to `return false` when you're certain that the
239
- * transition to the new props/state/context will not require a component
240
- * update.
241
- *
242
- * shouldComponentUpdate: function(nextProps, nextState, nextContext) {
243
- * return !equal(nextProps, this.props) ||
244
- * !equal(nextState, this.state) ||
245
- * !equal(nextContext, this.context);
246
- * }
247
- *
248
- * @param {object} nextProps
249
- * @param {?object} nextState
250
- * @param {?object} nextContext
251
- * @return {boolean} True if the component should update.
252
- * @optional
253
- */
254
- shouldComponentUpdate: SpecPolicy.DEFINE_ONCE,
255
-
256
- /**
257
- * Invoked when the component is about to update due to a transition from
258
- * `this.props`, `this.state` and `this.context` to `nextProps`, `nextState`
259
- * and `nextContext`.
260
- *
261
- * Use this as an opportunity to perform preparation before an update occurs.
262
- *
263
- * NOTE: You **cannot** use `this.setState()` in this method.
264
- *
265
- * @param {object} nextProps
266
- * @param {?object} nextState
267
- * @param {?object} nextContext
268
- * @param {ReactReconcileTransaction} transaction
269
- * @optional
270
- */
271
- componentWillUpdate: SpecPolicy.DEFINE_MANY,
272
-
273
- /**
274
- * Invoked when the component's DOM representation has been updated.
275
- *
276
- * Use this as an opportunity to operate on the DOM when the component has
277
- * been updated.
278
- *
279
- * @param {object} prevProps
280
- * @param {?object} prevState
281
- * @param {?object} prevContext
282
- * @param {DOMElement} rootNode DOM element representing the component.
283
- * @optional
284
- */
285
- componentDidUpdate: SpecPolicy.DEFINE_MANY,
286
-
287
- /**
288
- * Invoked when the component is about to be removed from its parent and have
289
- * its DOM representation destroyed.
290
- *
291
- * Use this as an opportunity to deallocate any external resources.
292
- *
293
- * NOTE: There is no `componentDidUnmount` since your component will have been
294
- * destroyed by that point.
295
- *
296
- * @optional
297
- */
298
- componentWillUnmount: SpecPolicy.DEFINE_MANY,
299
-
300
-
301
-
302
- // ==== Advanced methods ====
303
-
304
- /**
305
- * Updates the component's currently mounted DOM representation.
306
- *
307
- * By default, this implements React's rendering and reconciliation algorithm.
308
- * Sophisticated clients may wish to override this.
309
- *
310
- * @param {ReactReconcileTransaction} transaction
311
- * @internal
312
- * @overridable
313
- */
314
- updateComponent: SpecPolicy.OVERRIDE_BASE
315
-
316
- };
317
-
318
- /**
319
- * Mapping from class specification keys to special processing functions.
320
- *
321
- * Although these are declared like instance properties in the specification
322
- * when defining classes using `React.createClass`, they are actually static
323
- * and are accessible on the constructor instead of the prototype. Despite
324
- * being static, they must be defined outside of the "statics" key under
325
- * which all other static methods are defined.
326
- */
327
- var RESERVED_SPEC_KEYS = {
328
- displayName: function(Constructor, displayName) {
329
- Constructor.displayName = displayName;
330
- },
331
- mixins: function(Constructor, mixins) {
332
- if (mixins) {
333
- for (var i = 0; i < mixins.length; i++) {
334
- mixSpecIntoComponent(Constructor, mixins[i]);
335
- }
336
- }
337
- },
338
- childContextTypes: function(Constructor, childContextTypes) {
339
- validateTypeDef(
340
- Constructor,
341
- childContextTypes,
342
- ReactPropTypeLocations.childContext
343
- );
344
- Constructor.childContextTypes = assign(
345
- {},
346
- Constructor.childContextTypes,
347
- childContextTypes
348
- );
349
- },
350
- contextTypes: function(Constructor, contextTypes) {
351
- validateTypeDef(
352
- Constructor,
353
- contextTypes,
354
- ReactPropTypeLocations.context
355
- );
356
- Constructor.contextTypes = assign(
357
- {},
358
- Constructor.contextTypes,
359
- contextTypes
360
- );
361
- },
362
- /**
363
- * Special case getDefaultProps which should move into statics but requires
364
- * automatic merging.
365
- */
366
- getDefaultProps: function(Constructor, getDefaultProps) {
367
- if (Constructor.getDefaultProps) {
368
- Constructor.getDefaultProps = createMergedResultFunction(
369
- Constructor.getDefaultProps,
370
- getDefaultProps
371
- );
372
- } else {
373
- Constructor.getDefaultProps = getDefaultProps;
374
- }
375
- },
376
- propTypes: function(Constructor, propTypes) {
377
- validateTypeDef(
378
- Constructor,
379
- propTypes,
380
- ReactPropTypeLocations.prop
381
- );
382
- Constructor.propTypes = assign(
383
- {},
384
- Constructor.propTypes,
385
- propTypes
386
- );
387
- },
388
- statics: function(Constructor, statics) {
389
- mixStaticSpecIntoComponent(Constructor, statics);
390
- }
391
- };
392
-
393
34
  function getDeclarationErrorAddendum(component) {
394
- var owner = component._owner || null;
395
- if (owner && owner.constructor && owner.constructor.displayName) {
396
- return ' Check the render method of `' + owner.constructor.displayName +
397
- '`.';
398
- }
399
- return '';
400
- }
401
-
402
- function validateTypeDef(Constructor, typeDef, location) {
403
- for (var propName in typeDef) {
404
- if (typeDef.hasOwnProperty(propName)) {
405
- ("production" !== process.env.NODE_ENV ? invariant(
406
- typeof typeDef[propName] == 'function',
407
- '%s: %s type `%s` is invalid; it must be a function, usually from ' +
408
- 'React.PropTypes.',
409
- Constructor.displayName || 'ReactCompositeComponent',
410
- ReactPropTypeLocationNames[location],
411
- propName
412
- ) : invariant(typeof typeDef[propName] == 'function'));
35
+ var owner = component._currentElement._owner || null;
36
+ if (owner) {
37
+ var name = owner.getName();
38
+ if (name) {
39
+ return ' Check the render method of `' + name + '`.';
413
40
  }
414
41
  }
415
- }
416
-
417
- function validateMethodOverride(proto, name) {
418
- var specPolicy = ReactCompositeComponentInterface.hasOwnProperty(name) ?
419
- ReactCompositeComponentInterface[name] :
420
- null;
421
-
422
- // Disallow overriding of base class methods unless explicitly allowed.
423
- if (ReactCompositeComponentMixin.hasOwnProperty(name)) {
424
- ("production" !== process.env.NODE_ENV ? invariant(
425
- specPolicy === SpecPolicy.OVERRIDE_BASE,
426
- 'ReactCompositeComponentInterface: You are attempting to override ' +
427
- '`%s` from your class specification. Ensure that your method names ' +
428
- 'do not overlap with React methods.',
429
- name
430
- ) : invariant(specPolicy === SpecPolicy.OVERRIDE_BASE));
431
- }
432
-
433
- // Disallow defining methods more than once unless explicitly allowed.
434
- if (proto.hasOwnProperty(name)) {
435
- ("production" !== process.env.NODE_ENV ? invariant(
436
- specPolicy === SpecPolicy.DEFINE_MANY ||
437
- specPolicy === SpecPolicy.DEFINE_MANY_MERGED,
438
- 'ReactCompositeComponentInterface: You are attempting to define ' +
439
- '`%s` on your component more than once. This conflict may be due ' +
440
- 'to a mixin.',
441
- name
442
- ) : invariant(specPolicy === SpecPolicy.DEFINE_MANY ||
443
- specPolicy === SpecPolicy.DEFINE_MANY_MERGED));
444
- }
445
- }
446
-
447
- function validateLifeCycleOnReplaceState(instance) {
448
- var compositeLifeCycleState = instance._compositeLifeCycleState;
449
- ("production" !== process.env.NODE_ENV ? invariant(
450
- instance.isMounted() ||
451
- compositeLifeCycleState === CompositeLifeCycle.MOUNTING,
452
- 'replaceState(...): Can only update a mounted or mounting component.'
453
- ) : invariant(instance.isMounted() ||
454
- compositeLifeCycleState === CompositeLifeCycle.MOUNTING));
455
- ("production" !== process.env.NODE_ENV ? invariant(
456
- ReactCurrentOwner.current == null,
457
- 'replaceState(...): Cannot update during an existing state transition ' +
458
- '(such as within `render`). Render methods should be a pure function ' +
459
- 'of props and state.'
460
- ) : invariant(ReactCurrentOwner.current == null));
461
- ("production" !== process.env.NODE_ENV ? invariant(compositeLifeCycleState !== CompositeLifeCycle.UNMOUNTING,
462
- 'replaceState(...): Cannot update while unmounting component. This ' +
463
- 'usually means you called setState() on an unmounted component.'
464
- ) : invariant(compositeLifeCycleState !== CompositeLifeCycle.UNMOUNTING));
465
- }
466
-
467
- /**
468
- * Mixin helper which handles policy validation and reserved
469
- * specification keys when building `ReactCompositeComponent` classses.
470
- */
471
- function mixSpecIntoComponent(Constructor, spec) {
472
- if (!spec) {
473
- return;
474
- }
475
-
476
- ("production" !== process.env.NODE_ENV ? invariant(
477
- !ReactLegacyElement.isValidFactory(spec),
478
- 'ReactCompositeComponent: You\'re attempting to ' +
479
- 'use a component class as a mixin. Instead, just use a regular object.'
480
- ) : invariant(!ReactLegacyElement.isValidFactory(spec)));
481
- ("production" !== process.env.NODE_ENV ? invariant(
482
- !ReactElement.isValidElement(spec),
483
- 'ReactCompositeComponent: You\'re attempting to ' +
484
- 'use a component as a mixin. Instead, just use a regular object.'
485
- ) : invariant(!ReactElement.isValidElement(spec)));
486
-
487
- var proto = Constructor.prototype;
488
-
489
- // By handling mixins before any other properties, we ensure the same
490
- // chaining order is applied to methods with DEFINE_MANY policy, whether
491
- // mixins are listed before or after these methods in the spec.
492
- if (spec.hasOwnProperty(MIXINS_KEY)) {
493
- RESERVED_SPEC_KEYS.mixins(Constructor, spec.mixins);
494
- }
495
-
496
- for (var name in spec) {
497
- if (!spec.hasOwnProperty(name)) {
498
- continue;
499
- }
500
-
501
- if (name === MIXINS_KEY) {
502
- // We have already handled mixins in a special case above
503
- continue;
504
- }
505
-
506
- var property = spec[name];
507
- validateMethodOverride(proto, name);
508
-
509
- if (RESERVED_SPEC_KEYS.hasOwnProperty(name)) {
510
- RESERVED_SPEC_KEYS[name](Constructor, property);
511
- } else {
512
- // Setup methods on prototype:
513
- // The following member methods should not be automatically bound:
514
- // 1. Expected ReactCompositeComponent methods (in the "interface").
515
- // 2. Overridden methods (that were mixed in).
516
- var isCompositeComponentMethod =
517
- ReactCompositeComponentInterface.hasOwnProperty(name);
518
- var isAlreadyDefined = proto.hasOwnProperty(name);
519
- var markedDontBind = property && property.__reactDontBind;
520
- var isFunction = typeof property === 'function';
521
- var shouldAutoBind =
522
- isFunction &&
523
- !isCompositeComponentMethod &&
524
- !isAlreadyDefined &&
525
- !markedDontBind;
526
-
527
- if (shouldAutoBind) {
528
- if (!proto.__reactAutoBindMap) {
529
- proto.__reactAutoBindMap = {};
530
- }
531
- proto.__reactAutoBindMap[name] = property;
532
- proto[name] = property;
533
- } else {
534
- if (isAlreadyDefined) {
535
- var specPolicy = ReactCompositeComponentInterface[name];
536
-
537
- // These cases should already be caught by validateMethodOverride
538
- ("production" !== process.env.NODE_ENV ? invariant(
539
- isCompositeComponentMethod && (
540
- specPolicy === SpecPolicy.DEFINE_MANY_MERGED ||
541
- specPolicy === SpecPolicy.DEFINE_MANY
542
- ),
543
- 'ReactCompositeComponent: Unexpected spec policy %s for key %s ' +
544
- 'when mixing in component specs.',
545
- specPolicy,
546
- name
547
- ) : invariant(isCompositeComponentMethod && (
548
- specPolicy === SpecPolicy.DEFINE_MANY_MERGED ||
549
- specPolicy === SpecPolicy.DEFINE_MANY
550
- )));
551
-
552
- // For methods which are defined more than once, call the existing
553
- // methods before calling the new property, merging if appropriate.
554
- if (specPolicy === SpecPolicy.DEFINE_MANY_MERGED) {
555
- proto[name] = createMergedResultFunction(proto[name], property);
556
- } else if (specPolicy === SpecPolicy.DEFINE_MANY) {
557
- proto[name] = createChainedFunction(proto[name], property);
558
- }
559
- } else {
560
- proto[name] = property;
561
- if ("production" !== process.env.NODE_ENV) {
562
- // Add verbose displayName to the function, which helps when looking
563
- // at profiling tools.
564
- if (typeof property === 'function' && spec.displayName) {
565
- proto[name].displayName = spec.displayName + '_' + name;
566
- }
567
- }
568
- }
569
- }
570
- }
571
- }
572
- }
573
-
574
- function mixStaticSpecIntoComponent(Constructor, statics) {
575
- if (!statics) {
576
- return;
577
- }
578
- for (var name in statics) {
579
- var property = statics[name];
580
- if (!statics.hasOwnProperty(name)) {
581
- continue;
582
- }
583
-
584
- var isReserved = name in RESERVED_SPEC_KEYS;
585
- ("production" !== process.env.NODE_ENV ? invariant(
586
- !isReserved,
587
- 'ReactCompositeComponent: You are attempting to define a reserved ' +
588
- 'property, `%s`, that shouldn\'t be on the "statics" key. Define it ' +
589
- 'as an instance property instead; it will still be accessible on the ' +
590
- 'constructor.',
591
- name
592
- ) : invariant(!isReserved));
593
-
594
- var isInherited = name in Constructor;
595
- ("production" !== process.env.NODE_ENV ? invariant(
596
- !isInherited,
597
- 'ReactCompositeComponent: You are attempting to define ' +
598
- '`%s` on your component more than once. This conflict may be ' +
599
- 'due to a mixin.',
600
- name
601
- ) : invariant(!isInherited));
602
- Constructor[name] = property;
603
- }
42
+ return '';
604
43
  }
605
44
 
606
45
  /**
607
- * Merge two objects, but throw if both contain the same key.
46
+ * ------------------ The Life-Cycle of a Composite Component ------------------
608
47
  *
609
- * @param {object} one The first object, which is mutated.
610
- * @param {object} two The second object
611
- * @return {object} one after it has been mutated to contain everything in two.
612
- */
613
- function mergeObjectsWithNoDuplicateKeys(one, two) {
614
- ("production" !== process.env.NODE_ENV ? invariant(
615
- one && two && typeof one === 'object' && typeof two === 'object',
616
- 'mergeObjectsWithNoDuplicateKeys(): Cannot merge non-objects'
617
- ) : invariant(one && two && typeof one === 'object' && typeof two === 'object'));
618
-
619
- mapObject(two, function(value, key) {
620
- ("production" !== process.env.NODE_ENV ? invariant(
621
- one[key] === undefined,
622
- 'mergeObjectsWithNoDuplicateKeys(): ' +
623
- 'Tried to merge two objects with the same key: `%s`. This conflict ' +
624
- 'may be due to a mixin; in particular, this may be caused by two ' +
625
- 'getInitialState() or getDefaultProps() methods returning objects ' +
626
- 'with clashing keys.',
627
- key
628
- ) : invariant(one[key] === undefined));
629
- one[key] = value;
630
- });
631
- return one;
632
- }
633
-
634
- /**
635
- * Creates a function that invokes two functions and merges their return values.
48
+ * - constructor: Initialization of state. The instance is now retained.
49
+ * - componentWillMount
50
+ * - render
51
+ * - [children's constructors]
52
+ * - [children's componentWillMount and render]
53
+ * - [children's componentDidMount]
54
+ * - componentDidMount
636
55
  *
637
- * @param {function} one Function to invoke first.
638
- * @param {function} two Function to invoke second.
639
- * @return {function} Function that invokes the two argument functions.
640
- * @private
641
- */
642
- function createMergedResultFunction(one, two) {
643
- return function mergedResult() {
644
- var a = one.apply(this, arguments);
645
- var b = two.apply(this, arguments);
646
- if (a == null) {
647
- return b;
648
- } else if (b == null) {
649
- return a;
650
- }
651
- return mergeObjectsWithNoDuplicateKeys(a, b);
652
- };
653
- }
654
-
655
- /**
656
- * Creates a function that invokes two functions and ignores their return vales.
56
+ * Update Phases:
57
+ * - componentWillReceiveProps (only called if parent updated)
58
+ * - shouldComponentUpdate
59
+ * - componentWillUpdate
60
+ * - render
61
+ * - [children's constructors or receive props phases]
62
+ * - componentDidUpdate
657
63
  *
658
- * @param {function} one Function to invoke first.
659
- * @param {function} two Function to invoke second.
660
- * @return {function} Function that invokes the two argument functions.
661
- * @private
64
+ * - componentWillUnmount
65
+ * - [children's componentWillUnmount]
66
+ * - [children destroyed]
67
+ * - (destroyed): The instance is now blank, released by React and ready for GC.
68
+ *
69
+ * -----------------------------------------------------------------------------
662
70
  */
663
- function createChainedFunction(one, two) {
664
- return function chainedFunction() {
665
- one.apply(this, arguments);
666
- two.apply(this, arguments);
667
- };
668
- }
669
71
 
670
72
  /**
671
- * `ReactCompositeComponent` maintains an auxiliary life cycle state in
672
- * `this._compositeLifeCycleState` (which can be null).
73
+ * An incrementing ID assigned to each component when it is mounted. This is
74
+ * used to enforce the order in which `ReactUpdates` updates dirty components.
673
75
  *
674
- * This is different from the life cycle state maintained by `ReactComponent` in
675
- * `this._lifeCycleState`. The following diagram shows how the states overlap in
676
- * time. There are times when the CompositeLifeCycle is null - at those times it
677
- * is only meaningful to look at ComponentLifeCycle alone.
678
- *
679
- * Top Row: ReactComponent.ComponentLifeCycle
680
- * Low Row: ReactComponent.CompositeLifeCycle
681
- *
682
- * +-------+---------------------------------+--------+
683
- * | UN | MOUNTED | UN |
684
- * |MOUNTED| | MOUNTED|
685
- * +-------+---------------------------------+--------+
686
- * | ^--------+ +-------+ +--------^ |
687
- * | | | | | | | |
688
- * | 0--|MOUNTING|-0-|RECEIVE|-0-| UN |--->0 |
689
- * | | | |PROPS | |MOUNTING| |
690
- * | | | | | | | |
691
- * | | | | | | | |
692
- * | +--------+ +-------+ +--------+ |
693
- * | | | |
694
- * +-------+---------------------------------+--------+
76
+ * @private
695
77
  */
696
- var CompositeLifeCycle = keyMirror({
697
- /**
698
- * Components in the process of being mounted respond to state changes
699
- * differently.
700
- */
701
- MOUNTING: null,
702
- /**
703
- * Components in the process of being unmounted are guarded against state
704
- * changes.
705
- */
706
- UNMOUNTING: null,
707
- /**
708
- * Components that are mounted and receiving new props respond to state
709
- * changes differently.
710
- */
711
- RECEIVING_PROPS: null
712
- });
78
+ var nextMountID = 1;
713
79
 
714
80
  /**
715
81
  * @lends {ReactCompositeComponent.prototype}
@@ -724,29 +90,24 @@ var ReactCompositeComponentMixin = {
724
90
  * @internal
725
91
  */
726
92
  construct: function(element) {
727
- // Children can be either an array or more than one argument
728
- ReactComponent.Mixin.construct.apply(this, arguments);
729
- ReactOwner.Mixin.construct.apply(this, arguments);
93
+ this._currentElement = element;
94
+ this._rootNodeID = null;
95
+ this._instance = null;
730
96
 
731
- this.state = null;
732
- this._pendingState = null;
97
+ // See ReactUpdateQueue
98
+ this._pendingElement = null;
99
+ this._pendingStateQueue = null;
100
+ this._pendingReplaceState = false;
101
+ this._pendingForceUpdate = false;
733
102
 
734
- // This is the public post-processed context. The real context and pending
735
- // context lives on the element.
736
- this.context = null;
103
+ this._renderedComponent = null;
737
104
 
738
- this._compositeLifeCycleState = null;
739
- },
105
+ this._context = null;
106
+ this._mountOrder = 0;
107
+ this._isTopLevel = false;
740
108
 
741
- /**
742
- * Checks whether or not this composite component is mounted.
743
- * @return {boolean} True if mounted, false otherwise.
744
- * @protected
745
- * @final
746
- */
747
- isMounted: function() {
748
- return ReactComponent.Mixin.isMounted.call(this) &&
749
- this._compositeLifeCycleState !== CompositeLifeCycle.MOUNTING;
109
+ // See ReactUpdates and ReactUpdateQueue.
110
+ this._pendingCallbacks = null;
750
111
  },
751
112
 
752
113
  /**
@@ -754,68 +115,123 @@ var ReactCompositeComponentMixin = {
754
115
  *
755
116
  * @param {string} rootID DOM ID of the root node.
756
117
  * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
757
- * @param {number} mountDepth number of components in the owner hierarchy
758
118
  * @return {?string} Rendered markup to be inserted into the DOM.
759
119
  * @final
760
120
  * @internal
761
121
  */
762
- mountComponent: ReactPerf.measure(
763
- 'ReactCompositeComponent',
764
- 'mountComponent',
765
- function(rootID, transaction, mountDepth) {
766
- ReactComponent.Mixin.mountComponent.call(
767
- this,
768
- rootID,
769
- transaction,
770
- mountDepth
771
- );
772
- this._compositeLifeCycleState = CompositeLifeCycle.MOUNTING;
122
+ mountComponent: function(rootID, transaction, context) {
123
+ this._context = context;
124
+ this._mountOrder = nextMountID++;
125
+ this._rootNodeID = rootID;
773
126
 
774
- if (this.__reactAutoBindMap) {
775
- this._bindAutoBindMethods();
776
- }
127
+ var publicProps = this._processProps(this._currentElement.props);
128
+ var publicContext = this._processContext(this._currentElement._context);
777
129
 
778
- this.context = this._processContext(this._currentElement._context);
779
- this.props = this._processProps(this.props);
130
+ var Component = ReactNativeComponent.getComponentClassForElement(
131
+ this._currentElement
132
+ );
780
133
 
781
- this.state = this.getInitialState ? this.getInitialState() : null;
782
- ("production" !== process.env.NODE_ENV ? invariant(
783
- typeof this.state === 'object' && !Array.isArray(this.state),
784
- '%s.getInitialState(): must return an object or null',
785
- this.constructor.displayName || 'ReactCompositeComponent'
786
- ) : invariant(typeof this.state === 'object' && !Array.isArray(this.state)));
134
+ // Initialize the public class
135
+ var inst = new Component(publicProps, publicContext);
136
+ // These should be set up in the constructor, but as a convenience for
137
+ // simpler class abstractions, we set them up after the fact.
138
+ inst.props = publicProps;
139
+ inst.context = publicContext;
140
+ inst.refs = emptyObject;
787
141
 
788
- this._pendingState = null;
789
- this._pendingForceUpdate = false;
142
+ this._instance = inst;
143
+
144
+ // Store a reference from the instance back to the internal representation
145
+ ReactInstanceMap.set(inst, this);
146
+
147
+ if ("production" !== process.env.NODE_ENV) {
148
+ this._warnIfContextsDiffer(this._currentElement._context, context);
149
+ }
790
150
 
791
- if (this.componentWillMount) {
792
- this.componentWillMount();
151
+ if ("production" !== process.env.NODE_ENV) {
152
+ // Since plain JS classes are defined without any special initialization
153
+ // logic, we can not catch common errors early. Therefore, we have to
154
+ // catch them here, at initialization time, instead.
155
+ ("production" !== process.env.NODE_ENV ? warning(
156
+ !inst.getInitialState ||
157
+ inst.getInitialState.isReactClassApproved,
158
+ 'getInitialState was defined on %s, a plain JavaScript class. ' +
159
+ 'This is only supported for classes created using React.createClass. ' +
160
+ 'Did you mean to define a state property instead?',
161
+ this.getName() || 'a component'
162
+ ) : null);
163
+ ("production" !== process.env.NODE_ENV ? warning(
164
+ !inst.propTypes,
165
+ 'propTypes was defined as an instance property on %s. Use a static ' +
166
+ 'property to define propTypes instead.',
167
+ this.getName() || 'a component'
168
+ ) : null);
169
+ ("production" !== process.env.NODE_ENV ? warning(
170
+ !inst.contextTypes,
171
+ 'contextTypes was defined as an instance property on %s. Use a ' +
172
+ 'static property to define contextTypes instead.',
173
+ this.getName() || 'a component'
174
+ ) : null);
175
+ ("production" !== process.env.NODE_ENV ? warning(
176
+ typeof inst.componentShouldUpdate !== 'function',
177
+ '%s has a method called ' +
178
+ 'componentShouldUpdate(). Did you mean shouldComponentUpdate()? ' +
179
+ 'The name is phrased as a question because the function is ' +
180
+ 'expected to return a value.',
181
+ (this.getName() || 'A component')
182
+ ) : null);
183
+ }
184
+
185
+ var initialState = inst.state;
186
+ if (initialState === undefined) {
187
+ inst.state = initialState = null;
188
+ }
189
+ ("production" !== process.env.NODE_ENV ? invariant(
190
+ typeof initialState === 'object' && !Array.isArray(initialState),
191
+ '%s.state: must be set to an object or null',
192
+ this.getName() || 'ReactCompositeComponent'
193
+ ) : invariant(typeof initialState === 'object' && !Array.isArray(initialState)));
194
+
195
+ this._pendingStateQueue = null;
196
+ this._pendingReplaceState = false;
197
+ this._pendingForceUpdate = false;
198
+
199
+ var renderedElement;
200
+
201
+ var previouslyMounting = ReactLifeCycle.currentlyMountingInstance;
202
+ ReactLifeCycle.currentlyMountingInstance = this;
203
+ try {
204
+ if (inst.componentWillMount) {
205
+ inst.componentWillMount();
793
206
  // When mounting, calls to `setState` by `componentWillMount` will set
794
- // `this._pendingState` without triggering a re-render.
795
- if (this._pendingState) {
796
- this.state = this._pendingState;
797
- this._pendingState = null;
207
+ // `this._pendingStateQueue` without triggering a re-render.
208
+ if (this._pendingStateQueue) {
209
+ inst.state = this._processPendingState(inst.props, inst.context);
798
210
  }
799
211
  }
800
212
 
801
- this._renderedComponent = instantiateReactComponent(
802
- this._renderValidatedComponent(),
803
- this._currentElement.type // The wrapping type
804
- );
213
+ renderedElement = this._renderValidatedComponent();
214
+ } finally {
215
+ ReactLifeCycle.currentlyMountingInstance = previouslyMounting;
216
+ }
805
217
 
806
- // Done with mounting, `setState` will now trigger UI changes.
807
- this._compositeLifeCycleState = null;
808
- var markup = this._renderedComponent.mountComponent(
809
- rootID,
810
- transaction,
811
- mountDepth + 1
812
- );
813
- if (this.componentDidMount) {
814
- transaction.getReactMountReady().enqueue(this.componentDidMount, this);
815
- }
816
- return markup;
218
+ this._renderedComponent = this._instantiateReactComponent(
219
+ renderedElement,
220
+ this._currentElement.type // The wrapping type
221
+ );
222
+
223
+ var markup = ReactReconciler.mountComponent(
224
+ this._renderedComponent,
225
+ rootID,
226
+ transaction,
227
+ this._processChildContext(context)
228
+ );
229
+ if (inst.componentDidMount) {
230
+ transaction.getReactMountReady().enqueue(inst.componentDidMount, inst);
817
231
  }
818
- ),
232
+
233
+ return markup;
234
+ },
819
235
 
820
236
  /**
821
237
  * Releases any resources allocated by `mountComponent`.
@@ -824,83 +240,88 @@ var ReactCompositeComponentMixin = {
824
240
  * @internal
825
241
  */
826
242
  unmountComponent: function() {
827
- this._compositeLifeCycleState = CompositeLifeCycle.UNMOUNTING;
828
- if (this.componentWillUnmount) {
829
- this.componentWillUnmount();
243
+ var inst = this._instance;
244
+
245
+ if (inst.componentWillUnmount) {
246
+ var previouslyUnmounting = ReactLifeCycle.currentlyUnmountingInstance;
247
+ ReactLifeCycle.currentlyUnmountingInstance = this;
248
+ try {
249
+ inst.componentWillUnmount();
250
+ } finally {
251
+ ReactLifeCycle.currentlyUnmountingInstance = previouslyUnmounting;
252
+ }
830
253
  }
831
- this._compositeLifeCycleState = null;
832
254
 
833
- this._renderedComponent.unmountComponent();
255
+ ReactReconciler.unmountComponent(this._renderedComponent);
834
256
  this._renderedComponent = null;
835
257
 
836
- ReactComponent.Mixin.unmountComponent.call(this);
258
+ // Reset pending fields
259
+ this._pendingStateQueue = null;
260
+ this._pendingReplaceState = false;
261
+ this._pendingForceUpdate = false;
262
+ this._pendingCallbacks = null;
263
+ this._pendingElement = null;
837
264
 
838
- // Some existing components rely on this.props even after they've been
265
+ // These fields do not really need to be reset since this object is no
266
+ // longer accessible.
267
+ this._context = null;
268
+ this._rootNodeID = null;
269
+
270
+ // Delete the reference from the instance to this internal representation
271
+ // which allow the internals to be properly cleaned up even if the user
272
+ // leaks a reference to the public instance.
273
+ ReactInstanceMap.remove(inst);
274
+
275
+ // Some existing components rely on inst.props even after they've been
839
276
  // destroyed (in event handlers).
840
- // TODO: this.props = null;
841
- // TODO: this.state = null;
277
+ // TODO: inst.props = null;
278
+ // TODO: inst.state = null;
279
+ // TODO: inst.context = null;
842
280
  },
843
281
 
844
282
  /**
845
- * Sets a subset of the state. Always use this or `replaceState` to mutate
846
- * state. You should treat `this.state` as immutable.
847
- *
848
- * There is no guarantee that `this.state` will be immediately updated, so
849
- * accessing `this.state` after calling this method may return the old value.
850
- *
851
- * There is no guarantee that calls to `setState` will run synchronously,
852
- * as they may eventually be batched together. You can provide an optional
853
- * callback that will be executed when the call to setState is actually
854
- * completed.
283
+ * Schedule a partial update to the props. Only used for internal testing.
855
284
  *
856
- * @param {object} partialState Next partial state to be merged with state.
857
- * @param {?function} callback Called after state is updated.
285
+ * @param {object} partialProps Subset of the next props.
286
+ * @param {?function} callback Called after props are updated.
858
287
  * @final
859
- * @protected
288
+ * @internal
860
289
  */
861
- setState: function(partialState, callback) {
862
- ("production" !== process.env.NODE_ENV ? invariant(
863
- typeof partialState === 'object' || partialState == null,
864
- 'setState(...): takes an object of state variables to update.'
865
- ) : invariant(typeof partialState === 'object' || partialState == null));
866
- if ("production" !== process.env.NODE_ENV){
867
- ("production" !== process.env.NODE_ENV ? warning(
868
- partialState != null,
869
- 'setState(...): You passed an undefined or null state object; ' +
870
- 'instead, use forceUpdate().'
871
- ) : null);
872
- }
873
- // Merge with `_pendingState` if it exists, otherwise with existing state.
874
- this.replaceState(
875
- assign({}, this._pendingState || this.state, partialState),
876
- callback
290
+ _setPropsInternal: function(partialProps, callback) {
291
+ // This is a deoptimized path. We optimize for always having an element.
292
+ // This creates an extra internal element.
293
+ var element = this._pendingElement || this._currentElement;
294
+ this._pendingElement = ReactElement.cloneAndReplaceProps(
295
+ element,
296
+ assign({}, element.props, partialProps)
877
297
  );
298
+ ReactUpdates.enqueueUpdate(this, callback);
878
299
  },
879
300
 
880
301
  /**
881
- * Replaces all of the state. Always use this or `setState` to mutate state.
882
- * You should treat `this.state` as immutable.
883
- *
884
- * There is no guarantee that `this.state` will be immediately updated, so
885
- * accessing `this.state` after calling this method may return the old value.
302
+ * Filters the context object to only contain keys specified in
303
+ * `contextTypes`
886
304
  *
887
- * @param {object} completeState Next state.
888
- * @param {?function} callback Called after state is updated.
889
- * @final
890
- * @protected
305
+ * @param {object} context
306
+ * @return {?object}
307
+ * @private
891
308
  */
892
- replaceState: function(completeState, callback) {
893
- validateLifeCycleOnReplaceState(this);
894
- this._pendingState = completeState;
895
- if (this._compositeLifeCycleState !== CompositeLifeCycle.MOUNTING) {
896
- // If we're in a componentWillMount handler, don't enqueue a rerender
897
- // because ReactUpdates assumes we're in a browser context (which is wrong
898
- // for server rendering) and we're about to do a render anyway.
899
- // TODO: The callback here is ignored when setState is called from
900
- // componentWillMount. Either fix it or disallow doing so completely in
901
- // favor of getInitialState.
902
- ReactUpdates.enqueueUpdate(this, callback);
309
+ _maskContext: function(context) {
310
+ var maskedContext = null;
311
+ // This really should be getting the component class for the element,
312
+ // but we know that we're not going to need it for built-ins.
313
+ if (typeof this._currentElement.type === 'string') {
314
+ return emptyObject;
315
+ }
316
+ var contextTypes = this._currentElement.type.contextTypes;
317
+ if (!contextTypes) {
318
+ return emptyObject;
903
319
  }
320
+ maskedContext = {};
321
+ for (var contextName in contextTypes) {
322
+ maskedContext[contextName] = context[contextName];
323
+ }
324
+ return maskedContext;
904
325
  },
905
326
 
906
327
  /**
@@ -912,16 +333,14 @@ var ReactCompositeComponentMixin = {
912
333
  * @private
913
334
  */
914
335
  _processContext: function(context) {
915
- var maskedContext = null;
916
- var contextTypes = this.constructor.contextTypes;
917
- if (contextTypes) {
918
- maskedContext = {};
919
- for (var contextName in contextTypes) {
920
- maskedContext[contextName] = context[contextName];
921
- }
922
- if ("production" !== process.env.NODE_ENV) {
336
+ var maskedContext = this._maskContext(context);
337
+ if ("production" !== process.env.NODE_ENV) {
338
+ var Component = ReactNativeComponent.getComponentClassForElement(
339
+ this._currentElement
340
+ );
341
+ if (Component.contextTypes) {
923
342
  this._checkPropTypes(
924
- contextTypes,
343
+ Component.contextTypes,
925
344
  maskedContext,
926
345
  ReactPropTypeLocations.context
927
346
  );
@@ -936,29 +355,29 @@ var ReactCompositeComponentMixin = {
936
355
  * @private
937
356
  */
938
357
  _processChildContext: function(currentContext) {
939
- var childContext = this.getChildContext && this.getChildContext();
940
- var displayName = this.constructor.displayName || 'ReactCompositeComponent';
358
+ var inst = this._instance;
359
+ var childContext = inst.getChildContext && inst.getChildContext();
941
360
  if (childContext) {
942
361
  ("production" !== process.env.NODE_ENV ? invariant(
943
- typeof this.constructor.childContextTypes === 'object',
362
+ typeof inst.constructor.childContextTypes === 'object',
944
363
  '%s.getChildContext(): childContextTypes must be defined in order to ' +
945
364
  'use getChildContext().',
946
- displayName
947
- ) : invariant(typeof this.constructor.childContextTypes === 'object'));
365
+ this.getName() || 'ReactCompositeComponent'
366
+ ) : invariant(typeof inst.constructor.childContextTypes === 'object'));
948
367
  if ("production" !== process.env.NODE_ENV) {
949
368
  this._checkPropTypes(
950
- this.constructor.childContextTypes,
369
+ inst.constructor.childContextTypes,
951
370
  childContext,
952
371
  ReactPropTypeLocations.childContext
953
372
  );
954
373
  }
955
374
  for (var name in childContext) {
956
375
  ("production" !== process.env.NODE_ENV ? invariant(
957
- name in this.constructor.childContextTypes,
376
+ name in inst.constructor.childContextTypes,
958
377
  '%s.getChildContext(): key "%s" is not defined in childContextTypes.',
959
- displayName,
378
+ this.getName() || 'ReactCompositeComponent',
960
379
  name
961
- ) : invariant(name in this.constructor.childContextTypes));
380
+ ) : invariant(name in inst.constructor.childContextTypes));
962
381
  }
963
382
  return assign({}, currentContext, childContext);
964
383
  }
@@ -976,9 +395,15 @@ var ReactCompositeComponentMixin = {
976
395
  */
977
396
  _processProps: function(newProps) {
978
397
  if ("production" !== process.env.NODE_ENV) {
979
- var propTypes = this.constructor.propTypes;
980
- if (propTypes) {
981
- this._checkPropTypes(propTypes, newProps, ReactPropTypeLocations.prop);
398
+ var Component = ReactNativeComponent.getComponentClassForElement(
399
+ this._currentElement
400
+ );
401
+ if (Component.propTypes) {
402
+ this._checkPropTypes(
403
+ Component.propTypes,
404
+ newProps,
405
+ ReactPropTypeLocations.prop
406
+ );
982
407
  }
983
408
  }
984
409
  return newProps;
@@ -995,103 +420,236 @@ var ReactCompositeComponentMixin = {
995
420
  _checkPropTypes: function(propTypes, props, location) {
996
421
  // TODO: Stop validating prop types here and only use the element
997
422
  // validation.
998
- var componentName = this.constructor.displayName;
423
+ var componentName = this.getName();
999
424
  for (var propName in propTypes) {
1000
425
  if (propTypes.hasOwnProperty(propName)) {
1001
- var error =
1002
- propTypes[propName](props, propName, componentName, location);
426
+ var error;
427
+ try {
428
+ // This is intentionally an invariant that gets caught. It's the same
429
+ // behavior as without this statement except with a better message.
430
+ ("production" !== process.env.NODE_ENV ? invariant(
431
+ typeof propTypes[propName] === 'function',
432
+ '%s: %s type `%s` is invalid; it must be a function, usually ' +
433
+ 'from React.PropTypes.',
434
+ componentName || 'React class',
435
+ ReactPropTypeLocationNames[location],
436
+ propName
437
+ ) : invariant(typeof propTypes[propName] === 'function'));
438
+ error = propTypes[propName](props, propName, componentName, location);
439
+ } catch (ex) {
440
+ error = ex;
441
+ }
1003
442
  if (error instanceof Error) {
1004
443
  // We may want to extend this logic for similar errors in
1005
- // renderComponent calls, so I'm abstracting it away into
444
+ // React.render calls, so I'm abstracting it away into
1006
445
  // a function to minimize refactoring in the future
1007
446
  var addendum = getDeclarationErrorAddendum(this);
1008
- ("production" !== process.env.NODE_ENV ? warning(false, error.message + addendum) : null);
447
+
448
+ if (location === ReactPropTypeLocations.prop) {
449
+ // Preface gives us something to blacklist in warning module
450
+ ("production" !== process.env.NODE_ENV ? warning(
451
+ false,
452
+ 'Failed Composite propType: %s',
453
+ error.message + addendum
454
+ ) : null);
455
+ } else {
456
+ ("production" !== process.env.NODE_ENV ? warning(
457
+ false,
458
+ 'Failed Context Types: %s',
459
+ error.message + addendum
460
+ ) : null);
461
+ }
1009
462
  }
1010
463
  }
1011
464
  }
1012
465
  },
1013
466
 
467
+ receiveComponent: function(nextElement, transaction, nextContext) {
468
+ var prevElement = this._currentElement;
469
+ var prevContext = this._context;
470
+
471
+ this._pendingElement = null;
472
+
473
+ this.updateComponent(
474
+ transaction,
475
+ prevElement,
476
+ nextElement,
477
+ prevContext,
478
+ nextContext
479
+ );
480
+ },
481
+
1014
482
  /**
1015
- * If any of `_pendingElement`, `_pendingState`, or `_pendingForceUpdate`
483
+ * If any of `_pendingElement`, `_pendingStateQueue`, or `_pendingForceUpdate`
1016
484
  * is set, update the component.
1017
485
  *
1018
486
  * @param {ReactReconcileTransaction} transaction
1019
487
  * @internal
1020
488
  */
1021
489
  performUpdateIfNecessary: function(transaction) {
1022
- var compositeLifeCycleState = this._compositeLifeCycleState;
1023
- // Do not trigger a state transition if we are in the middle of mounting or
1024
- // receiving props because both of those will already be doing this.
1025
- if (compositeLifeCycleState === CompositeLifeCycle.MOUNTING ||
1026
- compositeLifeCycleState === CompositeLifeCycle.RECEIVING_PROPS) {
1027
- return;
490
+ if (this._pendingElement != null) {
491
+ ReactReconciler.receiveComponent(
492
+ this,
493
+ this._pendingElement || this._currentElement,
494
+ transaction,
495
+ this._context
496
+ );
1028
497
  }
1029
498
 
1030
- if (this._pendingElement == null &&
1031
- this._pendingState == null &&
1032
- !this._pendingForceUpdate) {
1033
- return;
499
+ if (this._pendingStateQueue !== null || this._pendingForceUpdate) {
500
+ if ("production" !== process.env.NODE_ENV) {
501
+ ReactElementValidator.checkAndWarnForMutatedProps(
502
+ this._currentElement
503
+ );
504
+ }
505
+
506
+ this.updateComponent(
507
+ transaction,
508
+ this._currentElement,
509
+ this._currentElement,
510
+ this._context,
511
+ this._context
512
+ );
1034
513
  }
514
+ },
1035
515
 
1036
- var nextContext = this.context;
1037
- var nextProps = this.props;
1038
- var nextElement = this._currentElement;
1039
- if (this._pendingElement != null) {
1040
- nextElement = this._pendingElement;
1041
- nextContext = this._processContext(nextElement._context);
1042
- nextProps = this._processProps(nextElement.props);
1043
- this._pendingElement = null;
1044
-
1045
- this._compositeLifeCycleState = CompositeLifeCycle.RECEIVING_PROPS;
1046
- if (this.componentWillReceiveProps) {
1047
- this.componentWillReceiveProps(nextProps, nextContext);
1048
- }
516
+ /**
517
+ * Compare two contexts, warning if they are different
518
+ * TODO: Remove this check when owner-context is removed
519
+ */
520
+ _warnIfContextsDiffer: function(ownerBasedContext, parentBasedContext) {
521
+ ownerBasedContext = this._maskContext(ownerBasedContext);
522
+ parentBasedContext = this._maskContext(parentBasedContext);
523
+ var parentKeys = Object.keys(parentBasedContext).sort();
524
+ var displayName = this.getName() || 'ReactCompositeComponent';
525
+ for (var i = 0; i < parentKeys.length; i++) {
526
+ var key = parentKeys[i];
527
+ ("production" !== process.env.NODE_ENV ? warning(
528
+ ownerBasedContext[key] === parentBasedContext[key],
529
+ 'owner-based and parent-based contexts differ ' +
530
+ '(values: `%s` vs `%s`) for key (%s) while mounting %s ' +
531
+ '(see: http://fb.me/react-context-by-parent)',
532
+ ownerBasedContext[key],
533
+ parentBasedContext[key],
534
+ key,
535
+ displayName
536
+ ) : null);
1049
537
  }
538
+ },
539
+
540
+ /**
541
+ * Perform an update to a mounted component. The componentWillReceiveProps and
542
+ * shouldComponentUpdate methods are called, then (assuming the update isn't
543
+ * skipped) the remaining update lifecycle methods are called and the DOM
544
+ * representation is updated.
545
+ *
546
+ * By default, this implements React's rendering and reconciliation algorithm.
547
+ * Sophisticated clients may wish to override this.
548
+ *
549
+ * @param {ReactReconcileTransaction} transaction
550
+ * @param {ReactElement} prevParentElement
551
+ * @param {ReactElement} nextParentElement
552
+ * @internal
553
+ * @overridable
554
+ */
555
+ updateComponent: function(
556
+ transaction,
557
+ prevParentElement,
558
+ nextParentElement,
559
+ prevUnmaskedContext,
560
+ nextUnmaskedContext
561
+ ) {
562
+ var inst = this._instance;
563
+
564
+ var nextContext = inst.context;
565
+ var nextProps = inst.props;
1050
566
 
1051
- this._compositeLifeCycleState = null;
567
+ // Distinguish between a props update versus a simple state update
568
+ if (prevParentElement !== nextParentElement) {
569
+ nextContext = this._processContext(nextParentElement._context);
570
+ nextProps = this._processProps(nextParentElement.props);
1052
571
 
1053
- var nextState = this._pendingState || this.state;
1054
- this._pendingState = null;
572
+ if ("production" !== process.env.NODE_ENV) {
573
+ if (nextUnmaskedContext != null) {
574
+ this._warnIfContextsDiffer(
575
+ nextParentElement._context,
576
+ nextUnmaskedContext
577
+ );
578
+ }
579
+ }
580
+
581
+ // An update here will schedule an update but immediately set
582
+ // _pendingStateQueue which will ensure that any state updates gets
583
+ // immediately reconciled instead of waiting for the next batch.
584
+
585
+ if (inst.componentWillReceiveProps) {
586
+ inst.componentWillReceiveProps(nextProps, nextContext);
587
+ }
588
+ }
589
+
590
+ var nextState = this._processPendingState(nextProps, nextContext);
1055
591
 
1056
592
  var shouldUpdate =
1057
593
  this._pendingForceUpdate ||
1058
- !this.shouldComponentUpdate ||
1059
- this.shouldComponentUpdate(nextProps, nextState, nextContext);
594
+ !inst.shouldComponentUpdate ||
595
+ inst.shouldComponentUpdate(nextProps, nextState, nextContext);
1060
596
 
1061
597
  if ("production" !== process.env.NODE_ENV) {
1062
- if (typeof shouldUpdate === "undefined") {
1063
- console.warn(
1064
- (this.constructor.displayName || 'ReactCompositeComponent') +
1065
- '.shouldComponentUpdate(): Returned undefined instead of a ' +
1066
- 'boolean value. Make sure to return true or false.'
1067
- );
1068
- }
598
+ ("production" !== process.env.NODE_ENV ? warning(
599
+ typeof shouldUpdate !== 'undefined',
600
+ '%s.shouldComponentUpdate(): Returned undefined instead of a ' +
601
+ 'boolean value. Make sure to return true or false.',
602
+ this.getName() || 'ReactCompositeComponent'
603
+ ) : null);
1069
604
  }
1070
605
 
1071
606
  if (shouldUpdate) {
1072
607
  this._pendingForceUpdate = false;
1073
608
  // Will set `this.props`, `this.state` and `this.context`.
1074
609
  this._performComponentUpdate(
1075
- nextElement,
610
+ nextParentElement,
1076
611
  nextProps,
1077
612
  nextState,
1078
613
  nextContext,
1079
- transaction
614
+ transaction,
615
+ nextUnmaskedContext
1080
616
  );
1081
617
  } else {
1082
618
  // If it's determined that a component should not update, we still want
1083
- // to set props and state.
1084
- this._currentElement = nextElement;
1085
- this.props = nextProps;
1086
- this.state = nextState;
1087
- this.context = nextContext;
1088
-
1089
- // Owner cannot change because shouldUpdateReactComponent doesn't allow
1090
- // it. TODO: Remove this._owner completely.
1091
- this._owner = nextElement._owner;
619
+ // to set props and state but we shortcut the rest of the update.
620
+ this._currentElement = nextParentElement;
621
+ this._context = nextUnmaskedContext;
622
+ inst.props = nextProps;
623
+ inst.state = nextState;
624
+ inst.context = nextContext;
1092
625
  }
1093
626
  },
1094
627
 
628
+ _processPendingState: function(props, context) {
629
+ var inst = this._instance;
630
+ var queue = this._pendingStateQueue;
631
+ var replace = this._pendingReplaceState;
632
+ this._pendingReplaceState = false;
633
+ this._pendingStateQueue = null;
634
+
635
+ if (!queue) {
636
+ return inst.state;
637
+ }
638
+
639
+ var nextState = assign({}, replace ? queue[0] : inst.state);
640
+ for (var i = replace ? 1 : 0; i < queue.length; i++) {
641
+ var partial = queue[i];
642
+ assign(
643
+ nextState,
644
+ typeof partial === 'function' ?
645
+ partial.call(inst, nextState, props, context) :
646
+ partial
647
+ );
648
+ }
649
+
650
+ return nextState;
651
+ },
652
+
1095
653
  /**
1096
654
  * Merges new props and state, notifies delegate methods of update and
1097
655
  * performs update.
@@ -1101,6 +659,7 @@ var ReactCompositeComponentMixin = {
1101
659
  * @param {?object} nextState Next object to set as state.
1102
660
  * @param {?object} nextContext Next public object to set as context.
1103
661
  * @param {ReactReconcileTransaction} transaction
662
+ * @param {?object} unmaskedContext
1104
663
  * @private
1105
664
  */
1106
665
  _performComponentUpdate: function(
@@ -1108,329 +667,204 @@ var ReactCompositeComponentMixin = {
1108
667
  nextProps,
1109
668
  nextState,
1110
669
  nextContext,
1111
- transaction
670
+ transaction,
671
+ unmaskedContext
1112
672
  ) {
1113
- var prevElement = this._currentElement;
1114
- var prevProps = this.props;
1115
- var prevState = this.state;
1116
- var prevContext = this.context;
673
+ var inst = this._instance;
1117
674
 
1118
- if (this.componentWillUpdate) {
1119
- this.componentWillUpdate(nextProps, nextState, nextContext);
675
+ var prevProps = inst.props;
676
+ var prevState = inst.state;
677
+ var prevContext = inst.context;
678
+
679
+ if (inst.componentWillUpdate) {
680
+ inst.componentWillUpdate(nextProps, nextState, nextContext);
1120
681
  }
1121
682
 
1122
683
  this._currentElement = nextElement;
1123
- this.props = nextProps;
1124
- this.state = nextState;
1125
- this.context = nextContext;
1126
-
1127
- // Owner cannot change because shouldUpdateReactComponent doesn't allow
1128
- // it. TODO: Remove this._owner completely.
1129
- this._owner = nextElement._owner;
684
+ this._context = unmaskedContext;
685
+ inst.props = nextProps;
686
+ inst.state = nextState;
687
+ inst.context = nextContext;
1130
688
 
1131
- this.updateComponent(
1132
- transaction,
1133
- prevElement
1134
- );
689
+ this._updateRenderedComponent(transaction, unmaskedContext);
1135
690
 
1136
- if (this.componentDidUpdate) {
691
+ if (inst.componentDidUpdate) {
1137
692
  transaction.getReactMountReady().enqueue(
1138
- this.componentDidUpdate.bind(this, prevProps, prevState, prevContext),
1139
- this
693
+ inst.componentDidUpdate.bind(inst, prevProps, prevState, prevContext),
694
+ inst
1140
695
  );
1141
696
  }
1142
697
  },
1143
698
 
1144
- receiveComponent: function(nextElement, transaction) {
1145
- if (nextElement === this._currentElement &&
1146
- nextElement._owner != null) {
1147
- // Since elements are immutable after the owner is rendered,
1148
- // we can do a cheap identity compare here to determine if this is a
1149
- // superfluous reconcile. It's possible for state to be mutable but such
1150
- // change should trigger an update of the owner which would recreate
1151
- // the element. We explicitly check for the existence of an owner since
1152
- // it's possible for a element created outside a composite to be
1153
- // deeply mutated and reused.
1154
- return;
1155
- }
1156
-
1157
- ReactComponent.Mixin.receiveComponent.call(
1158
- this,
1159
- nextElement,
1160
- transaction
1161
- );
1162
- },
1163
-
1164
699
  /**
1165
- * Updates the component's currently mounted DOM representation.
1166
- *
1167
- * By default, this implements React's rendering and reconciliation algorithm.
1168
- * Sophisticated clients may wish to override this.
700
+ * Call the component's `render` method and update the DOM accordingly.
1169
701
  *
1170
702
  * @param {ReactReconcileTransaction} transaction
1171
- * @param {ReactElement} prevElement
1172
703
  * @internal
1173
- * @overridable
1174
704
  */
1175
- updateComponent: ReactPerf.measure(
1176
- 'ReactCompositeComponent',
1177
- 'updateComponent',
1178
- function(transaction, prevParentElement) {
1179
- ReactComponent.Mixin.updateComponent.call(
1180
- this,
705
+ _updateRenderedComponent: function(transaction, context) {
706
+ var prevComponentInstance = this._renderedComponent;
707
+ var prevRenderedElement = prevComponentInstance._currentElement;
708
+ var nextRenderedElement = this._renderValidatedComponent();
709
+ if (shouldUpdateReactComponent(prevRenderedElement, nextRenderedElement)) {
710
+ ReactReconciler.receiveComponent(
711
+ prevComponentInstance,
712
+ nextRenderedElement,
1181
713
  transaction,
1182
- prevParentElement
714
+ this._processChildContext(context)
1183
715
  );
1184
-
1185
- var prevComponentInstance = this._renderedComponent;
1186
- var prevElement = prevComponentInstance._currentElement;
1187
- var nextElement = this._renderValidatedComponent();
1188
- if (shouldUpdateReactComponent(prevElement, nextElement)) {
1189
- prevComponentInstance.receiveComponent(nextElement, transaction);
1190
- } else {
1191
- // These two IDs are actually the same! But nothing should rely on that.
1192
- var thisID = this._rootNodeID;
1193
- var prevComponentID = prevComponentInstance._rootNodeID;
1194
- prevComponentInstance.unmountComponent();
1195
- this._renderedComponent = instantiateReactComponent(
1196
- nextElement,
1197
- this._currentElement.type
1198
- );
1199
- var nextMarkup = this._renderedComponent.mountComponent(
1200
- thisID,
1201
- transaction,
1202
- this._mountDepth + 1
1203
- );
1204
- ReactComponent.BackendIDOperations.dangerouslyReplaceNodeWithMarkupByID(
1205
- prevComponentID,
1206
- nextMarkup
1207
- );
1208
- }
716
+ } else {
717
+ // These two IDs are actually the same! But nothing should rely on that.
718
+ var thisID = this._rootNodeID;
719
+ var prevComponentID = prevComponentInstance._rootNodeID;
720
+ ReactReconciler.unmountComponent(prevComponentInstance);
721
+
722
+ this._renderedComponent = this._instantiateReactComponent(
723
+ nextRenderedElement,
724
+ this._currentElement.type
725
+ );
726
+ var nextMarkup = ReactReconciler.mountComponent(
727
+ this._renderedComponent,
728
+ thisID,
729
+ transaction,
730
+ context
731
+ );
732
+ this._replaceNodeWithMarkupByID(prevComponentID, nextMarkup);
1209
733
  }
1210
- ),
734
+ },
1211
735
 
1212
736
  /**
1213
- * Forces an update. This should only be invoked when it is known with
1214
- * certainty that we are **not** in a DOM transaction.
1215
- *
1216
- * You may want to call this when you know that some deeper aspect of the
1217
- * component's state has changed but `setState` was not called.
1218
- *
1219
- * This will not invoke `shouldUpdateComponent`, but it will invoke
1220
- * `componentWillUpdate` and `componentDidUpdate`.
1221
- *
1222
- * @param {?function} callback Called after update is complete.
1223
- * @final
1224
737
  * @protected
1225
738
  */
1226
- forceUpdate: function(callback) {
1227
- var compositeLifeCycleState = this._compositeLifeCycleState;
1228
- ("production" !== process.env.NODE_ENV ? invariant(
1229
- this.isMounted() ||
1230
- compositeLifeCycleState === CompositeLifeCycle.MOUNTING,
1231
- 'forceUpdate(...): Can only force an update on mounted or mounting ' +
1232
- 'components.'
1233
- ) : invariant(this.isMounted() ||
1234
- compositeLifeCycleState === CompositeLifeCycle.MOUNTING));
1235
- ("production" !== process.env.NODE_ENV ? invariant(
1236
- compositeLifeCycleState !== CompositeLifeCycle.UNMOUNTING &&
1237
- ReactCurrentOwner.current == null,
1238
- 'forceUpdate(...): Cannot force an update while unmounting component ' +
1239
- 'or within a `render` function.'
1240
- ) : invariant(compositeLifeCycleState !== CompositeLifeCycle.UNMOUNTING &&
1241
- ReactCurrentOwner.current == null));
1242
- this._pendingForceUpdate = true;
1243
- ReactUpdates.enqueueUpdate(this, callback);
739
+ _replaceNodeWithMarkupByID: function(prevComponentID, nextMarkup) {
740
+ ReactComponentEnvironment.replaceNodeWithMarkupByID(
741
+ prevComponentID,
742
+ nextMarkup
743
+ );
1244
744
  },
1245
745
 
1246
746
  /**
1247
- * @private
747
+ * @protected
1248
748
  */
1249
- _renderValidatedComponent: ReactPerf.measure(
1250
- 'ReactCompositeComponent',
1251
- '_renderValidatedComponent',
1252
- function() {
1253
- var renderedComponent;
1254
- var previousContext = ReactContext.current;
1255
- ReactContext.current = this._processChildContext(
1256
- this._currentElement._context
1257
- );
1258
- ReactCurrentOwner.current = this;
1259
- try {
1260
- renderedComponent = this.render();
1261
- if (renderedComponent === null || renderedComponent === false) {
1262
- renderedComponent = ReactEmptyComponent.getEmptyComponent();
1263
- ReactEmptyComponent.registerNullComponentID(this._rootNodeID);
1264
- } else {
1265
- ReactEmptyComponent.deregisterNullComponentID(this._rootNodeID);
1266
- }
1267
- } finally {
1268
- ReactContext.current = previousContext;
1269
- ReactCurrentOwner.current = null;
749
+ _renderValidatedComponentWithoutOwnerOrContext: function() {
750
+ var inst = this._instance;
751
+ var renderedComponent = inst.render();
752
+ if ("production" !== process.env.NODE_ENV) {
753
+ // We allow auto-mocks to proceed as if they're returning null.
754
+ if (typeof renderedComponent === 'undefined' &&
755
+ inst.render._isMockFunction) {
756
+ // This is probably bad practice. Consider warning here and
757
+ // deprecating this convenience.
758
+ renderedComponent = null;
1270
759
  }
1271
- ("production" !== process.env.NODE_ENV ? invariant(
1272
- ReactElement.isValidElement(renderedComponent),
1273
- '%s.render(): A valid ReactComponent must be returned. You may have ' +
1274
- 'returned undefined, an array or some other invalid object.',
1275
- this.constructor.displayName || 'ReactCompositeComponent'
1276
- ) : invariant(ReactElement.isValidElement(renderedComponent)));
1277
- return renderedComponent;
1278
760
  }
1279
- ),
761
+
762
+ return renderedComponent;
763
+ },
1280
764
 
1281
765
  /**
1282
766
  * @private
1283
767
  */
1284
- _bindAutoBindMethods: function() {
1285
- for (var autoBindKey in this.__reactAutoBindMap) {
1286
- if (!this.__reactAutoBindMap.hasOwnProperty(autoBindKey)) {
1287
- continue;
1288
- }
1289
- var method = this.__reactAutoBindMap[autoBindKey];
1290
- this[autoBindKey] = this._bindAutoBindMethod(ReactErrorUtils.guard(
1291
- method,
1292
- this.constructor.displayName + '.' + autoBindKey
1293
- ));
768
+ _renderValidatedComponent: function() {
769
+ var renderedComponent;
770
+ var previousContext = ReactContext.current;
771
+ ReactContext.current = this._processChildContext(
772
+ this._currentElement._context
773
+ );
774
+ ReactCurrentOwner.current = this;
775
+ try {
776
+ renderedComponent =
777
+ this._renderValidatedComponentWithoutOwnerOrContext();
778
+ } finally {
779
+ ReactContext.current = previousContext;
780
+ ReactCurrentOwner.current = null;
1294
781
  }
782
+ ("production" !== process.env.NODE_ENV ? invariant(
783
+ // TODO: An `isValidNode` function would probably be more appropriate
784
+ renderedComponent === null || renderedComponent === false ||
785
+ ReactElement.isValidElement(renderedComponent),
786
+ '%s.render(): A valid ReactComponent must be returned. You may have ' +
787
+ 'returned undefined, an array or some other invalid object.',
788
+ this.getName() || 'ReactCompositeComponent'
789
+ ) : invariant(// TODO: An `isValidNode` function would probably be more appropriate
790
+ renderedComponent === null || renderedComponent === false ||
791
+ ReactElement.isValidElement(renderedComponent)));
792
+ return renderedComponent;
1295
793
  },
1296
794
 
1297
795
  /**
1298
- * Binds a method to the component.
796
+ * Lazily allocates the refs object and stores `component` as `ref`.
1299
797
  *
1300
- * @param {function} method Method to be bound.
798
+ * @param {string} ref Reference name.
799
+ * @param {component} component Component to store as `ref`.
800
+ * @final
1301
801
  * @private
1302
802
  */
1303
- _bindAutoBindMethod: function(method) {
1304
- var component = this;
1305
- var boundMethod = method.bind(component);
1306
- if ("production" !== process.env.NODE_ENV) {
1307
- boundMethod.__reactBoundContext = component;
1308
- boundMethod.__reactBoundMethod = method;
1309
- boundMethod.__reactBoundArguments = null;
1310
- var componentName = component.constructor.displayName;
1311
- var _bind = boundMethod.bind;
1312
- boundMethod.bind = function(newThis ) {for (var args=[],$__0=1,$__1=arguments.length;$__0<$__1;$__0++) args.push(arguments[$__0]);
1313
- // User is trying to bind() an autobound method; we effectively will
1314
- // ignore the value of "this" that the user is trying to use, so
1315
- // let's warn.
1316
- if (newThis !== component && newThis !== null) {
1317
- monitorCodeUse('react_bind_warning', { component: componentName });
1318
- console.warn(
1319
- 'bind(): React component methods may only be bound to the ' +
1320
- 'component instance. See ' + componentName
1321
- );
1322
- } else if (!args.length) {
1323
- monitorCodeUse('react_bind_warning', { component: componentName });
1324
- console.warn(
1325
- 'bind(): You are binding a component method to the component. ' +
1326
- 'React does this for you automatically in a high-performance ' +
1327
- 'way, so you can safely remove this call. See ' + componentName
1328
- );
1329
- return boundMethod;
1330
- }
1331
- var reboundMethod = _bind.apply(boundMethod, arguments);
1332
- reboundMethod.__reactBoundContext = component;
1333
- reboundMethod.__reactBoundMethod = method;
1334
- reboundMethod.__reactBoundArguments = args;
1335
- return reboundMethod;
1336
- };
1337
- }
1338
- return boundMethod;
1339
- }
1340
- };
1341
-
1342
- var ReactCompositeComponentBase = function() {};
1343
- assign(
1344
- ReactCompositeComponentBase.prototype,
1345
- ReactComponent.Mixin,
1346
- ReactOwner.Mixin,
1347
- ReactPropTransferer.Mixin,
1348
- ReactCompositeComponentMixin
1349
- );
1350
-
1351
- /**
1352
- * Module for creating composite components.
1353
- *
1354
- * @class ReactCompositeComponent
1355
- * @extends ReactComponent
1356
- * @extends ReactOwner
1357
- * @extends ReactPropTransferer
1358
- */
1359
- var ReactCompositeComponent = {
1360
-
1361
- LifeCycle: CompositeLifeCycle,
1362
-
1363
- Base: ReactCompositeComponentBase,
803
+ attachRef: function(ref, component) {
804
+ var inst = this.getPublicInstance();
805
+ var refs = inst.refs === emptyObject ? (inst.refs = {}) : inst.refs;
806
+ refs[ref] = component.getPublicInstance();
807
+ },
1364
808
 
1365
809
  /**
1366
- * Creates a composite component class given a class specification.
810
+ * Detaches a reference name.
1367
811
  *
1368
- * @param {object} spec Class specification (which must define `render`).
1369
- * @return {function} Component constructor function.
1370
- * @public
812
+ * @param {string} ref Name to dereference.
813
+ * @final
814
+ * @private
1371
815
  */
1372
- createClass: function(spec) {
1373
- var Constructor = function(props) {
1374
- // This constructor is overridden by mocks. The argument is used
1375
- // by mocks to assert on what gets mounted. This will later be used
1376
- // by the stand-alone class implementation.
1377
- };
1378
- Constructor.prototype = new ReactCompositeComponentBase();
1379
- Constructor.prototype.constructor = Constructor;
1380
-
1381
- injectedMixins.forEach(
1382
- mixSpecIntoComponent.bind(null, Constructor)
816
+ detachRef: function(ref) {
817
+ var refs = this.getPublicInstance().refs;
818
+ delete refs[ref];
819
+ },
820
+
821
+ /**
822
+ * Get a text description of the component that can be used to identify it
823
+ * in error messages.
824
+ * @return {string} The name or null.
825
+ * @internal
826
+ */
827
+ getName: function() {
828
+ var type = this._currentElement.type;
829
+ var constructor = this._instance && this._instance.constructor;
830
+ return (
831
+ type.displayName || (constructor && constructor.displayName) ||
832
+ type.name || (constructor && constructor.name) ||
833
+ null
1383
834
  );
835
+ },
1384
836
 
1385
- mixSpecIntoComponent(Constructor, spec);
837
+ /**
838
+ * Get the publicly accessible representation of this component - i.e. what
839
+ * is exposed by refs and returned by React.render. Can be null for stateless
840
+ * components.
841
+ *
842
+ * @return {ReactComponent} the public component instance.
843
+ * @internal
844
+ */
845
+ getPublicInstance: function() {
846
+ return this._instance;
847
+ },
1386
848
 
1387
- // Initialize the defaultProps property after all mixins have been merged
1388
- if (Constructor.getDefaultProps) {
1389
- Constructor.defaultProps = Constructor.getDefaultProps();
1390
- }
849
+ // Stub
850
+ _instantiateReactComponent: null
1391
851
 
1392
- ("production" !== process.env.NODE_ENV ? invariant(
1393
- Constructor.prototype.render,
1394
- 'createClass(...): Class specification must implement a `render` method.'
1395
- ) : invariant(Constructor.prototype.render));
852
+ };
1396
853
 
1397
- if ("production" !== process.env.NODE_ENV) {
1398
- if (Constructor.prototype.componentShouldUpdate) {
1399
- monitorCodeUse(
1400
- 'react_component_should_update_warning',
1401
- { component: spec.displayName }
1402
- );
1403
- console.warn(
1404
- (spec.displayName || 'A component') + ' has a method called ' +
1405
- 'componentShouldUpdate(). Did you mean shouldComponentUpdate()? ' +
1406
- 'The name is phrased as a question because the function is ' +
1407
- 'expected to return a value.'
1408
- );
1409
- }
1410
- }
854
+ ReactPerf.measureMethods(
855
+ ReactCompositeComponentMixin,
856
+ 'ReactCompositeComponent',
857
+ {
858
+ mountComponent: 'mountComponent',
859
+ updateComponent: 'updateComponent',
860
+ _renderValidatedComponent: '_renderValidatedComponent'
861
+ }
862
+ );
1411
863
 
1412
- // Reduce time spent doing lookups by setting these on the prototype.
1413
- for (var methodName in ReactCompositeComponentInterface) {
1414
- if (!Constructor.prototype[methodName]) {
1415
- Constructor.prototype[methodName] = null;
1416
- }
1417
- }
864
+ var ReactCompositeComponent = {
1418
865
 
1419
- if ("production" !== process.env.NODE_ENV) {
1420
- return ReactLegacyElement.wrapFactory(
1421
- ReactElementValidator.createFactory(Constructor)
1422
- );
1423
- }
1424
- return ReactLegacyElement.wrapFactory(
1425
- ReactElement.createFactory(Constructor)
1426
- );
1427
- },
866
+ Mixin: ReactCompositeComponentMixin
1428
867
 
1429
- injection: {
1430
- injectMixin: function(mixin) {
1431
- injectedMixins.push(mixin);
1432
- }
1433
- }
1434
868
  };
1435
869
 
1436
870
  module.exports = ReactCompositeComponent;