react 0.12.0 → 0.13.0-alpha.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 (153) hide show
  1. package/dist/JSXTransformer.js +2345 -910
  2. package/dist/react-with-addons.js +5273 -4111
  3. package/dist/react-with-addons.min.js +5 -6
  4. package/dist/react.js +4840 -3940
  5. package/dist/react.min.js +5 -6
  6. package/lib/AutoFocusMixin.js +1 -1
  7. package/lib/BeforeInputEventPlugin.js +389 -112
  8. package/lib/CSSProperty.js +6 -3
  9. package/lib/CSSPropertyOperations.js +21 -1
  10. package/lib/CallbackQueue.js +2 -2
  11. package/lib/ChangeEventPlugin.js +3 -3
  12. package/lib/ClientReactRootIndex.js +1 -1
  13. package/lib/DOMChildrenOperations.js +6 -4
  14. package/lib/DOMProperty.js +1 -1
  15. package/lib/DOMPropertyOperations.js +1 -1
  16. package/lib/Danger.js +7 -6
  17. package/lib/DefaultEventPluginOrder.js +1 -2
  18. package/lib/EnterLeaveEventPlugin.js +1 -1
  19. package/lib/EventConstants.js +1 -1
  20. package/lib/EventPluginHub.js +9 -7
  21. package/lib/EventPluginRegistry.js +1 -1
  22. package/lib/EventPluginUtils.js +1 -1
  23. package/lib/EventPropagators.js +1 -1
  24. package/lib/ExecutionEnvironment.js +2 -3
  25. package/lib/FallbackCompositionState.js +89 -0
  26. package/lib/HTMLDOMPropertyConfig.js +19 -7
  27. package/lib/LinkedStateMixin.js +1 -1
  28. package/lib/LinkedValueUtils.js +3 -3
  29. package/lib/LocalEventTrapMixin.js +1 -1
  30. package/lib/MobileSafariClickEventPlugin.js +1 -1
  31. package/lib/Object.assign.js +3 -1
  32. package/lib/PooledClass.js +1 -1
  33. package/lib/React.js +17 -50
  34. package/lib/ReactBrowserComponentMixin.js +3 -13
  35. package/lib/ReactBrowserEventEmitter.js +4 -6
  36. package/lib/ReactCSSTransitionGroup.js +4 -1
  37. package/lib/ReactCSSTransitionGroupChild.js +12 -2
  38. package/lib/ReactChildReconciler.js +121 -0
  39. package/lib/ReactChildren.js +10 -8
  40. package/lib/ReactClass.js +874 -0
  41. package/lib/ReactComponent.js +45 -286
  42. package/lib/ReactComponentBase.js +126 -0
  43. package/lib/ReactComponentBrowserEnvironment.js +10 -83
  44. package/lib/ReactComponentEnvironment.js +57 -0
  45. package/lib/ReactComponentWithPureRenderMixin.js +1 -1
  46. package/lib/ReactCompositeComponent.js +700 -1045
  47. package/lib/ReactContext.js +6 -2
  48. package/lib/ReactCurrentOwner.js +1 -1
  49. package/lib/ReactDOM.js +3 -8
  50. package/lib/ReactDOMButton.js +5 -6
  51. package/lib/ReactDOMComponent.js +120 -77
  52. package/lib/ReactDOMForm.js +5 -6
  53. package/lib/ReactDOMIDOperations.js +56 -74
  54. package/lib/ReactDOMImg.js +4 -6
  55. package/lib/ReactDOMInput.js +5 -6
  56. package/lib/ReactDOMOption.js +5 -6
  57. package/lib/ReactDOMSelect.js +57 -65
  58. package/lib/ReactDOMSelection.js +6 -2
  59. package/lib/ReactDOMTextComponent.js +124 -0
  60. package/lib/ReactDOMTextarea.js +5 -6
  61. package/lib/ReactDefaultBatchingStrategy.js +1 -1
  62. package/lib/ReactDefaultInjection.js +14 -8
  63. package/lib/ReactDefaultPerf.js +8 -7
  64. package/lib/ReactDefaultPerfAnalysis.js +1 -1
  65. package/lib/ReactElement.js +22 -15
  66. package/lib/ReactElementValidator.js +192 -53
  67. package/lib/ReactEmptyComponent.js +29 -11
  68. package/lib/ReactEventEmitterMixin.js +1 -1
  69. package/lib/ReactEventListener.js +3 -3
  70. package/lib/ReactInjection.js +7 -5
  71. package/lib/ReactInputSelection.js +3 -4
  72. package/lib/ReactInstanceHandles.js +3 -2
  73. package/lib/ReactInstanceMap.js +47 -0
  74. package/lib/ReactLink.js +1 -1
  75. package/lib/ReactMarkupChecksum.js +1 -1
  76. package/lib/ReactMount.js +202 -66
  77. package/lib/ReactMultiChild.js +44 -45
  78. package/lib/ReactMultiChildUpdateTypes.js +1 -1
  79. package/lib/ReactNativeComponent.js +47 -10
  80. package/lib/ReactOwner.js +4 -48
  81. package/lib/ReactPerf.js +21 -1
  82. package/lib/ReactPropTransferer.js +2 -57
  83. package/lib/ReactPropTypeLocationNames.js +1 -1
  84. package/lib/ReactPropTypeLocations.js +1 -1
  85. package/lib/ReactPropTypes.js +14 -22
  86. package/lib/ReactPutListenerQueue.js +1 -1
  87. package/lib/ReactReconcileTransaction.js +1 -1
  88. package/lib/ReactRef.js +96 -0
  89. package/lib/ReactRootIndex.js +1 -1
  90. package/lib/ReactServerRendering.js +5 -3
  91. package/lib/ReactServerRenderingTransaction.js +1 -1
  92. package/lib/ReactStateSetters.js +1 -1
  93. package/lib/ReactTestUtils.js +83 -26
  94. package/lib/ReactTransitionChildMapping.js +1 -1
  95. package/lib/ReactTransitionEvents.js +1 -1
  96. package/lib/ReactTransitionGroup.js +48 -7
  97. package/lib/ReactUpdates.js +46 -45
  98. package/lib/ReactWithAddons.js +1 -1
  99. package/lib/SVGDOMPropertyConfig.js +1 -1
  100. package/lib/SelectEventPlugin.js +3 -3
  101. package/lib/ServerReactRootIndex.js +1 -1
  102. package/lib/SimpleEventPlugin.js +1 -1
  103. package/lib/SyntheticClipboardEvent.js +1 -2
  104. package/lib/SyntheticCompositionEvent.js +1 -2
  105. package/lib/SyntheticDragEvent.js +1 -1
  106. package/lib/SyntheticEvent.js +11 -3
  107. package/lib/SyntheticFocusEvent.js +1 -1
  108. package/lib/SyntheticInputEvent.js +1 -2
  109. package/lib/SyntheticKeyboardEvent.js +1 -1
  110. package/lib/SyntheticMouseEvent.js +2 -4
  111. package/lib/SyntheticTouchEvent.js +1 -1
  112. package/lib/SyntheticUIEvent.js +1 -1
  113. package/lib/SyntheticWheelEvent.js +1 -1
  114. package/lib/Transaction.js +3 -3
  115. package/lib/ViewportMetrics.js +2 -5
  116. package/lib/accumulate.js +47 -0
  117. package/lib/accumulateInto.js +1 -1
  118. package/lib/adler32.js +1 -1
  119. package/lib/cloneWithProps.js +3 -3
  120. package/lib/copyProperties.js +2 -0
  121. package/lib/createFullPageComponent.js +3 -3
  122. package/lib/dangerousStyleValue.js +1 -1
  123. package/lib/escapeTextForBrowser.js +6 -6
  124. package/lib/findDOMNode.js +51 -0
  125. package/lib/flattenChildren.js +11 -22
  126. package/lib/forEachAccumulated.js +1 -1
  127. package/lib/getEventCharCode.js +1 -1
  128. package/lib/getEventKey.js +1 -1
  129. package/lib/getEventModifierState.js +1 -1
  130. package/lib/getEventTarget.js +1 -1
  131. package/lib/getIteratorFn.js +42 -0
  132. package/lib/getNodeForCharacterOffset.js +2 -2
  133. package/lib/getReactRootElementInContainer.js +1 -1
  134. package/lib/getTextContentAccessor.js +1 -1
  135. package/lib/instantiateReactComponent.js +89 -66
  136. package/lib/isEventSupported.js +1 -1
  137. package/lib/isNode.js +3 -4
  138. package/lib/isTextInputElement.js +2 -3
  139. package/lib/joinClasses.js +1 -1
  140. package/lib/keyMirror.js +1 -1
  141. package/lib/memoizeStringOnly.js +4 -5
  142. package/lib/onlyChild.js +1 -1
  143. package/lib/setInnerHTML.js +12 -1
  144. package/lib/shallowEqual.js +1 -1
  145. package/lib/shouldUpdateReactComponent.js +48 -6
  146. package/lib/traverseAllChildren.js +111 -55
  147. package/lib/update.js +1 -1
  148. package/lib/warning.js +9 -2
  149. package/package.json +1 -1
  150. package/lib/CompositionEventPlugin.js +0 -257
  151. package/lib/ReactLegacyElement.js +0 -243
  152. package/lib/ReactTextComponent.js +0 -104
  153. package/lib/deprecated.js +0 -47
@@ -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, 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;
@@ -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
 
@@ -9,449 +9,39 @@
9
9
  * @providesModule ReactCompositeComponent
10
10
  */
11
11
 
12
- "use strict";
12
+ 'use strict';
13
13
 
14
14
  var ReactComponent = require("./ReactComponent");
15
+ var ReactComponentEnvironment = require("./ReactComponentEnvironment");
15
16
  var ReactContext = require("./ReactContext");
16
17
  var ReactCurrentOwner = require("./ReactCurrentOwner");
17
18
  var ReactElement = require("./ReactElement");
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");
23
20
  var ReactPerf = require("./ReactPerf");
24
- var ReactPropTransferer = require("./ReactPropTransferer");
25
21
  var ReactPropTypeLocations = require("./ReactPropTypeLocations");
26
22
  var ReactPropTypeLocationNames = require("./ReactPropTypeLocationNames");
27
23
  var ReactUpdates = require("./ReactUpdates");
28
24
 
29
25
  var assign = require("./Object.assign");
30
- var instantiateReactComponent = require("./instantiateReactComponent");
26
+ var emptyObject = require("./emptyObject");
31
27
  var invariant = require("./invariant");
32
28
  var keyMirror = require("./keyMirror");
33
- var keyOf = require("./keyOf");
34
- var monitorCodeUse = require("./monitorCodeUse");
35
- var mapObject = require("./mapObject");
36
29
  var shouldUpdateReactComponent = require("./shouldUpdateReactComponent");
37
30
  var warning = require("./warning");
38
31
 
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
32
  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'));
33
+ var owner = component._currentElement._owner || null;
34
+ if (owner) {
35
+ var name = owner.getName();
36
+ if (name) {
37
+ return ' Check the render method of `' + name + '`.';
413
38
  }
414
39
  }
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
- }
40
+ return '';
445
41
  }
446
42
 
447
43
  function validateLifeCycleOnReplaceState(instance) {
448
44
  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
45
  ("production" !== process.env.NODE_ENV ? invariant(
456
46
  ReactCurrentOwner.current == null,
457
47
  'replaceState(...): Cannot update during an existing state transition ' +
@@ -464,215 +54,12 @@ function validateLifeCycleOnReplaceState(instance) {
464
54
  ) : invariant(compositeLifeCycleState !== CompositeLifeCycle.UNMOUNTING));
465
55
  }
466
56
 
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
- }
604
- }
605
-
606
- /**
607
- * Merge two objects, but throw if both contain the same key.
608
- *
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.
636
- *
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.
657
- *
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
662
- */
663
- function createChainedFunction(one, two) {
664
- return function chainedFunction() {
665
- one.apply(this, arguments);
666
- two.apply(this, arguments);
667
- };
668
- }
669
-
670
57
  /**
671
58
  * `ReactCompositeComponent` maintains an auxiliary life cycle state in
672
59
  * `this._compositeLifeCycleState` (which can be null).
673
60
  *
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
61
+ * This is different from the life cycle state maintained by `ReactComponent`.
62
+ * The following diagram shows how the states overlap in
676
63
  * time. There are times when the CompositeLifeCycle is null - at those times it
677
64
  * is only meaningful to look at ComponentLifeCycle alone.
678
65
  *
@@ -711,10 +98,19 @@ var CompositeLifeCycle = keyMirror({
711
98
  RECEIVING_PROPS: null
712
99
  });
713
100
 
101
+ /**
102
+ * An incrementing ID assigned to each component when it is mounted. This is
103
+ * used to enforce the order in which `ReactUpdates` updates dirty components.
104
+ *
105
+ * @private
106
+ */
107
+ var nextMountID = 1;
108
+
714
109
  /**
715
110
  * @lends {ReactCompositeComponent.prototype}
716
111
  */
717
- var ReactCompositeComponentMixin = {
112
+ var ReactCompositeComponentMixin = assign({},
113
+ ReactComponent.Mixin, {
718
114
 
719
115
  /**
720
116
  * Base constructor for all composite component.
@@ -724,18 +120,30 @@ var ReactCompositeComponentMixin = {
724
120
  * @internal
725
121
  */
726
122
  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);
123
+ this._rootNodeID = null;
730
124
 
731
- this.state = null;
125
+ this._instance.props = element.props;
126
+ this._instance.state = null;
127
+ this._instance.context = null;
128
+ this._instance.refs = emptyObject;
129
+
130
+ this._pendingElement = null;
131
+ this._pendingContext = null;
732
132
  this._pendingState = null;
133
+ this._pendingForceUpdate = false;
134
+ this._compositeLifeCycleState = null;
733
135
 
734
- // This is the public post-processed context. The real context and pending
735
- // context lives on the element.
736
- this.context = null;
136
+ this._renderedComponent = null;
737
137
 
738
- this._compositeLifeCycleState = null;
138
+ // Children can be either an array or more than one argument
139
+ ReactComponent.Mixin.construct.apply(this, arguments);
140
+
141
+ this._context = null;
142
+ this._mountOrder = 0;
143
+ this._isTopLevel = false;
144
+
145
+ // See ReactUpdates.
146
+ this._pendingCallbacks = null;
739
147
  },
740
148
 
741
149
  /**
@@ -745,8 +153,7 @@ var ReactCompositeComponentMixin = {
745
153
  * @final
746
154
  */
747
155
  isMounted: function() {
748
- return ReactComponent.Mixin.isMounted.call(this) &&
749
- this._compositeLifeCycleState !== CompositeLifeCycle.MOUNTING;
156
+ return this._compositeLifeCycleState !== CompositeLifeCycle.MOUNTING;
750
157
  },
751
158
 
752
159
  /**
@@ -754,104 +161,234 @@ var ReactCompositeComponentMixin = {
754
161
  *
755
162
  * @param {string} rootID DOM ID of the root node.
756
163
  * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
757
- * @param {number} mountDepth number of components in the owner hierarchy
758
164
  * @return {?string} Rendered markup to be inserted into the DOM.
759
165
  * @final
760
166
  * @internal
761
167
  */
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;
168
+ mountComponent: function(rootID, transaction, context) {
169
+ ReactComponent.Mixin.mountComponent.call(
170
+ this,
171
+ rootID,
172
+ transaction,
173
+ context
174
+ );
773
175
 
774
- if (this.__reactAutoBindMap) {
775
- this._bindAutoBindMethods();
776
- }
176
+ this._context = context;
177
+ this._mountOrder = nextMountID++;
178
+ this._rootNodeID = rootID;
777
179
 
778
- this.context = this._processContext(this._currentElement._context);
779
- this.props = this._processProps(this.props);
180
+ var inst = this._instance;
780
181
 
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)));
787
-
788
- this._pendingState = null;
789
- this._pendingForceUpdate = false;
790
-
791
- if (this.componentWillMount) {
792
- this.componentWillMount();
793
- // 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;
798
- }
799
- }
182
+ // Store a reference from the instance back to the internal representation
183
+ ReactInstanceMap.set(inst, this);
800
184
 
801
- this._renderedComponent = instantiateReactComponent(
802
- this._renderValidatedComponent(),
803
- this._currentElement.type // The wrapping type
804
- );
185
+ this._compositeLifeCycleState = CompositeLifeCycle.MOUNTING;
805
186
 
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);
187
+ inst.context = this._processContext(this._currentElement._context);
188
+ if ("production" !== process.env.NODE_ENV) {
189
+ this._warnIfContextsDiffer(this._currentElement._context, context);
190
+ }
191
+ inst.props = this._processProps(this._currentElement.props);
192
+
193
+ var initialState = inst.getInitialState ? inst.getInitialState() : null;
194
+ if ("production" !== process.env.NODE_ENV) {
195
+ // We allow auto-mocks to proceed as if they're returning null.
196
+ if (typeof initialState === 'undefined' &&
197
+ inst.getInitialState._isMockFunction) {
198
+ // This is probably bad practice. Consider warning here and
199
+ // deprecating this convenience.
200
+ initialState = null;
201
+ }
202
+ // Since plain JS classes are defined without any special initialization
203
+ // logic, we can not catch common errors early. Therefore, we have to
204
+ // catch them here, at initialization time, instead.
205
+ ("production" !== process.env.NODE_ENV ? warning(
206
+ !inst.getInitialState ||
207
+ inst.getInitialState.isReactClassApproved,
208
+ 'getInitialState was defined on %s, a plain JavaScript class. ' +
209
+ 'This is only supported for classes created using React.createClass. ' +
210
+ 'Did you mean to define a state property instead?',
211
+ this.getName() || 'a component'
212
+ ) : null);
213
+ ("production" !== process.env.NODE_ENV ? warning(
214
+ !inst.componentWillMount ||
215
+ inst.componentWillMount.isReactClassApproved,
216
+ 'componentWillMount was defined on %s, a plain JavaScript class. ' +
217
+ 'This is only supported for classes created using React.createClass. ' +
218
+ 'Did you mean to define a constructor instead?',
219
+ this.getName() || 'a component'
220
+ ) : null);
221
+ ("production" !== process.env.NODE_ENV ? warning(
222
+ !inst.propTypes,
223
+ 'propTypes was defined as an instance property on %s. Use a static ' +
224
+ 'property to define propTypes instead.',
225
+ this.getName() || 'a component'
226
+ ) : null);
227
+ ("production" !== process.env.NODE_ENV ? warning(
228
+ !inst.contextTypes,
229
+ 'contextTypes was defined as an instance property on %s. Use a ' +
230
+ 'static property to define contextTypes instead.',
231
+ this.getName() || 'a component'
232
+ ) : null);
233
+ ("production" !== process.env.NODE_ENV ? warning(
234
+ typeof inst.componentShouldUpdate !== 'function',
235
+ '%s has a method called ' +
236
+ 'componentShouldUpdate(). Did you mean shouldComponentUpdate()? ' +
237
+ 'The name is phrased as a question because the function is ' +
238
+ 'expected to return a value.',
239
+ (this.getName() || 'A component')
240
+ ) : null);
241
+ }
242
+ ("production" !== process.env.NODE_ENV ? invariant(
243
+ typeof initialState === 'object' && !Array.isArray(initialState),
244
+ '%s.getInitialState(): must return an object or null',
245
+ this.getName() || 'ReactCompositeComponent'
246
+ ) : invariant(typeof initialState === 'object' && !Array.isArray(initialState)));
247
+ inst.state = initialState;
248
+
249
+ this._pendingState = null;
250
+ this._pendingForceUpdate = false;
251
+
252
+ if (inst.componentWillMount) {
253
+ inst.componentWillMount();
254
+ // When mounting, calls to `setState` by `componentWillMount` will set
255
+ // `this._pendingState` without triggering a re-render.
256
+ if (this._pendingState) {
257
+ inst.state = this._pendingState;
258
+ this._pendingState = null;
815
259
  }
816
- return markup;
817
260
  }
818
- ),
261
+
262
+ var renderedElement = this._renderValidatedComponent();
263
+ this._renderedComponent = this._instantiateReactComponent(
264
+ renderedElement,
265
+ this._currentElement.type // The wrapping type
266
+ );
267
+
268
+ // Done with mounting, `setState` will now trigger UI changes.
269
+ this._compositeLifeCycleState = null;
270
+ var markup = this._renderedComponent.mountComponent(
271
+ rootID,
272
+ transaction,
273
+ this._processChildContext(context)
274
+ );
275
+ if (inst.componentDidMount) {
276
+ transaction.getReactMountReady().enqueue(inst.componentDidMount, inst);
277
+ }
278
+ return markup;
279
+ },
280
+
281
+ /**
282
+ * Releases any resources allocated by `mountComponent`.
283
+ *
284
+ * @final
285
+ * @internal
286
+ */
287
+ unmountComponent: function() {
288
+ var inst = this._instance;
289
+
290
+ this._compositeLifeCycleState = CompositeLifeCycle.UNMOUNTING;
291
+ if (inst.componentWillUnmount) {
292
+ inst.componentWillUnmount();
293
+ }
294
+ this._compositeLifeCycleState = null;
295
+
296
+ this._renderedComponent.unmountComponent();
297
+ this._renderedComponent = null;
298
+
299
+ // Reset pending fields
300
+ this._pendingState = null;
301
+ this._pendingForceUpdate = false;
302
+ this._pendingCallbacks = null;
303
+ this._pendingElement = null;
304
+
305
+ ReactComponent.Mixin.unmountComponent.call(this);
306
+
307
+ ReactComponentEnvironment.unmountIDFromEnvironment(this._rootNodeID);
308
+
309
+ this._context = null;
310
+ this._rootNodeID = null;
311
+
312
+ // Delete the reference from the instance to this internal representation
313
+ // which allow the internals to be properly cleaned up even if the user
314
+ // leaks a reference to the public instance.
315
+ ReactInstanceMap.remove(inst);
316
+
317
+ // Some existing components rely on inst.props even after they've been
318
+ // destroyed (in event handlers).
319
+ // TODO: inst.props = null;
320
+ // TODO: inst.state = null;
321
+ // TODO: inst.context = null;
322
+ },
323
+
324
+ /**
325
+ * Sets a subset of the props.
326
+ *
327
+ * @param {object} partialProps Subset of the next props.
328
+ * @param {?function} callback Called after props are updated.
329
+ * @final
330
+ * @public
331
+ */
332
+ setProps: function(partialProps, callback) {
333
+ // Merge with the pending element if it exists, otherwise with existing
334
+ // element props.
335
+ var element = this._pendingElement || this._currentElement;
336
+ this.replaceProps(
337
+ assign({}, element.props, partialProps),
338
+ callback
339
+ );
340
+ },
341
+
342
+ /**
343
+ * Replaces all of the props.
344
+ *
345
+ * @param {object} props New props.
346
+ * @param {?function} callback Called after props are updated.
347
+ * @final
348
+ * @public
349
+ */
350
+ replaceProps: function(props, callback) {
351
+ ("production" !== process.env.NODE_ENV ? invariant(
352
+ this._isTopLevel,
353
+ 'replaceProps(...): You called `setProps` or `replaceProps` on a ' +
354
+ 'component with a parent. This is an anti-pattern since props will ' +
355
+ 'get reactively updated when rendered. Instead, change the owner\'s ' +
356
+ '`render` method to pass the correct value as props to the component ' +
357
+ 'where it is created.'
358
+ ) : invariant(this._isTopLevel));
359
+ // This is a deoptimized path. We optimize for always having an element.
360
+ // This creates an extra internal element.
361
+ this._pendingElement = ReactElement.cloneAndReplaceProps(
362
+ this._pendingElement || this._currentElement,
363
+ props
364
+ );
365
+ ReactUpdates.enqueueUpdate(this, callback);
366
+ },
819
367
 
820
368
  /**
821
- * Releases any resources allocated by `mountComponent`.
369
+ * Schedule a partial update to the props. Only used for internal testing.
822
370
  *
371
+ * @param {object} partialProps Subset of the next props.
372
+ * @param {?function} callback Called after props are updated.
823
373
  * @final
824
374
  * @internal
825
375
  */
826
- unmountComponent: function() {
827
- this._compositeLifeCycleState = CompositeLifeCycle.UNMOUNTING;
828
- if (this.componentWillUnmount) {
829
- this.componentWillUnmount();
830
- }
831
- this._compositeLifeCycleState = null;
832
-
833
- this._renderedComponent.unmountComponent();
834
- this._renderedComponent = null;
835
-
836
- ReactComponent.Mixin.unmountComponent.call(this);
837
-
838
- // Some existing components rely on this.props even after they've been
839
- // destroyed (in event handlers).
840
- // TODO: this.props = null;
841
- // TODO: this.state = null;
376
+ _setPropsInternal: function(partialProps, callback) {
377
+ // This is a deoptimized path. We optimize for always having an element.
378
+ // This creates an extra internal element.
379
+ var element = this._pendingElement || this._currentElement;
380
+ this._pendingElement = ReactElement.cloneAndReplaceProps(
381
+ element,
382
+ assign({}, element.props, partialProps)
383
+ );
384
+ ReactUpdates.enqueueUpdate(this, callback);
842
385
  },
843
386
 
844
387
  /**
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.
388
+ * Sets a subset of the state. This only exists because _pendingState is
389
+ * internal. This provides a merging strategy that is not available to deep
390
+ * properties which is confusing. TODO: Expose pendingState or don't use it
391
+ * during the merge.
855
392
  *
856
393
  * @param {object} partialState Next partial state to be merged with state.
857
394
  * @param {?function} callback Called after state is updated.
@@ -859,20 +396,9 @@ var ReactCompositeComponentMixin = {
859
396
  * @protected
860
397
  */
861
398
  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
399
  // Merge with `_pendingState` if it exists, otherwise with existing state.
874
400
  this.replaceState(
875
- assign({}, this._pendingState || this.state, partialState),
401
+ assign({}, this._pendingState || this._instance.state, partialState),
876
402
  callback
877
403
  );
878
404
  },
@@ -903,6 +429,33 @@ var ReactCompositeComponentMixin = {
903
429
  }
904
430
  },
905
431
 
432
+ /**
433
+ * Forces an update. This should only be invoked when it is known with
434
+ * certainty that we are **not** in a DOM transaction.
435
+ *
436
+ * You may want to call this when you know that some deeper aspect of the
437
+ * component's state has changed but `setState` was not called.
438
+ *
439
+ * This will not invoke `shouldUpdateComponent`, but it will invoke
440
+ * `componentWillUpdate` and `componentDidUpdate`.
441
+ *
442
+ * @param {?function} callback Called after update is complete.isM
443
+ * @final
444
+ * @protected
445
+ */
446
+ forceUpdate: function(callback) {
447
+ var compositeLifeCycleState = this._compositeLifeCycleState;
448
+ ("production" !== process.env.NODE_ENV ? invariant(
449
+ compositeLifeCycleState !== CompositeLifeCycle.RECEIVING_STATE &&
450
+ compositeLifeCycleState !== CompositeLifeCycle.UNMOUNTING,
451
+ 'forceUpdate(...): Cannot force an update while unmounting component ' +
452
+ 'or during an existing state transition (such as within `render`).'
453
+ ) : invariant(compositeLifeCycleState !== CompositeLifeCycle.RECEIVING_STATE &&
454
+ compositeLifeCycleState !== CompositeLifeCycle.UNMOUNTING));
455
+ this._pendingForceUpdate = true;
456
+ ReactUpdates.enqueueUpdate(this, callback);
457
+ },
458
+
906
459
  /**
907
460
  * Filters the context object to only contain keys specified in
908
461
  * `contextTypes`, and asserts that they are valid.
@@ -913,19 +466,20 @@ var ReactCompositeComponentMixin = {
913
466
  */
914
467
  _processContext: function(context) {
915
468
  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) {
923
- this._checkPropTypes(
924
- contextTypes,
925
- maskedContext,
926
- ReactPropTypeLocations.context
927
- );
928
- }
469
+ var contextTypes = this._instance.constructor.contextTypes;
470
+ if (!contextTypes) {
471
+ return emptyObject;
472
+ }
473
+ maskedContext = {};
474
+ for (var contextName in contextTypes) {
475
+ maskedContext[contextName] = context[contextName];
476
+ }
477
+ if ("production" !== process.env.NODE_ENV) {
478
+ this._checkPropTypes(
479
+ contextTypes,
480
+ maskedContext,
481
+ ReactPropTypeLocations.context
482
+ );
929
483
  }
930
484
  return maskedContext;
931
485
  },
@@ -936,29 +490,29 @@ var ReactCompositeComponentMixin = {
936
490
  * @private
937
491
  */
938
492
  _processChildContext: function(currentContext) {
939
- var childContext = this.getChildContext && this.getChildContext();
940
- var displayName = this.constructor.displayName || 'ReactCompositeComponent';
493
+ var inst = this._instance;
494
+ var childContext = inst.getChildContext && inst.getChildContext();
941
495
  if (childContext) {
942
496
  ("production" !== process.env.NODE_ENV ? invariant(
943
- typeof this.constructor.childContextTypes === 'object',
497
+ typeof inst.constructor.childContextTypes === 'object',
944
498
  '%s.getChildContext(): childContextTypes must be defined in order to ' +
945
499
  'use getChildContext().',
946
- displayName
947
- ) : invariant(typeof this.constructor.childContextTypes === 'object'));
500
+ this.getName() || 'ReactCompositeComponent'
501
+ ) : invariant(typeof inst.constructor.childContextTypes === 'object'));
948
502
  if ("production" !== process.env.NODE_ENV) {
949
503
  this._checkPropTypes(
950
- this.constructor.childContextTypes,
504
+ inst.constructor.childContextTypes,
951
505
  childContext,
952
506
  ReactPropTypeLocations.childContext
953
507
  );
954
508
  }
955
509
  for (var name in childContext) {
956
510
  ("production" !== process.env.NODE_ENV ? invariant(
957
- name in this.constructor.childContextTypes,
511
+ name in inst.constructor.childContextTypes,
958
512
  '%s.getChildContext(): key "%s" is not defined in childContextTypes.',
959
- displayName,
513
+ this.getName() || 'ReactCompositeComponent',
960
514
  name
961
- ) : invariant(name in this.constructor.childContextTypes));
515
+ ) : invariant(name in inst.constructor.childContextTypes));
962
516
  }
963
517
  return assign({}, currentContext, childContext);
964
518
  }
@@ -976,7 +530,8 @@ var ReactCompositeComponentMixin = {
976
530
  */
977
531
  _processProps: function(newProps) {
978
532
  if ("production" !== process.env.NODE_ENV) {
979
- var propTypes = this.constructor.propTypes;
533
+ var inst = this._instance;
534
+ var propTypes = inst.constructor.propTypes;
980
535
  if (propTypes) {
981
536
  this._checkPropTypes(propTypes, newProps, ReactPropTypeLocations.prop);
982
537
  }
@@ -995,14 +550,28 @@ var ReactCompositeComponentMixin = {
995
550
  _checkPropTypes: function(propTypes, props, location) {
996
551
  // TODO: Stop validating prop types here and only use the element
997
552
  // validation.
998
- var componentName = this.constructor.displayName;
553
+ var componentName = this.getName();
999
554
  for (var propName in propTypes) {
1000
555
  if (propTypes.hasOwnProperty(propName)) {
1001
- var error =
1002
- propTypes[propName](props, propName, componentName, location);
556
+ var error;
557
+ try {
558
+ // This is intentionally an invariant that gets caught. It's the same
559
+ // behavior as without this statement except with a better message.
560
+ ("production" !== process.env.NODE_ENV ? invariant(
561
+ typeof propTypes[propName] === 'function',
562
+ '%s: %s type `%s` is invalid; it must be a function, usually ' +
563
+ 'from React.PropTypes.',
564
+ componentName || 'React class',
565
+ ReactPropTypeLocationNames[location],
566
+ propName
567
+ ) : invariant(typeof propTypes[propName] === 'function'));
568
+ error = propTypes[propName](props, propName, componentName, location);
569
+ } catch (ex) {
570
+ error = ex;
571
+ }
1003
572
  if (error instanceof Error) {
1004
573
  // We may want to extend this logic for similar errors in
1005
- // renderComponent calls, so I'm abstracting it away into
574
+ // React.render calls, so I'm abstracting it away into
1006
575
  // a function to minimize refactoring in the future
1007
576
  var addendum = getDeclarationErrorAddendum(this);
1008
577
  ("production" !== process.env.NODE_ENV ? warning(false, error.message + addendum) : null);
@@ -1011,6 +580,24 @@ var ReactCompositeComponentMixin = {
1011
580
  }
1012
581
  },
1013
582
 
583
+ receiveComponent: function(nextElement, transaction, context) {
584
+ if (nextElement === this._currentElement &&
585
+ nextElement._owner != null) {
586
+ // Since elements are immutable after the owner is rendered,
587
+ // we can do a cheap identity compare here to determine if this is a
588
+ // superfluous reconcile. It's possible for state to be mutable but such
589
+ // change should trigger an update of the owner which would recreate
590
+ // the element. We explicitly check for the existence of an owner since
591
+ // it's possible for an element created outside a composite to be
592
+ // deeply mutated and reused.
593
+ return;
594
+ }
595
+
596
+ this._pendingElement = nextElement;
597
+ this._pendingContext = context;
598
+ this.performUpdateIfNecessary(transaction);
599
+ },
600
+
1014
601
  /**
1015
602
  * If any of `_pendingElement`, `_pendingState`, or `_pendingForceUpdate`
1016
603
  * is set, update the component.
@@ -1029,67 +616,167 @@ var ReactCompositeComponentMixin = {
1029
616
 
1030
617
  if (this._pendingElement == null &&
1031
618
  this._pendingState == null &&
619
+ this._pendingContext == null &&
1032
620
  !this._pendingForceUpdate) {
1033
621
  return;
1034
622
  }
1035
623
 
1036
- var nextContext = this.context;
1037
- var nextProps = this.props;
1038
- var nextElement = this._currentElement;
624
+ var prevElement = this._currentElement;
625
+ var nextElement = prevElement;
1039
626
  if (this._pendingElement != null) {
1040
627
  nextElement = this._pendingElement;
1041
- nextContext = this._processContext(nextElement._context);
1042
- nextProps = this._processProps(nextElement.props);
1043
628
  this._pendingElement = null;
629
+ }
630
+
631
+ var prevContext = this._context;
632
+ var nextContext = prevContext;
633
+ if (this._pendingContext != null) {
634
+ nextContext = this._pendingContext;
635
+ this._pendingContext = null;
636
+ }
637
+
638
+ this.updateComponent(
639
+ transaction,
640
+ prevElement,
641
+ nextElement,
642
+ prevContext,
643
+ nextContext
644
+ );
645
+ },
646
+
647
+ /**
648
+ * Compare two contexts, warning if they are different
649
+ * TODO: Remove this check when owner-context is removed
650
+ */
651
+ _warnIfContextsDiffer: function(ownerBasedContext, parentBasedContext) {
652
+ var ownerKeys = Object.keys(ownerBasedContext).sort();
653
+ var parentKeys = Object.keys(parentBasedContext).sort();
654
+ var displayName = this.getName() || 'ReactCompositeComponent';
655
+ if (ownerKeys.length !== parentKeys.length ||
656
+ ownerKeys.toString() !== parentKeys.toString()) {
657
+ ("production" !== process.env.NODE_ENV ? warning(
658
+ ownerKeys.length === parentKeys.length &&
659
+ ownerKeys.toString() === parentKeys.toString(),
660
+ 'owner based context (keys: %s) does not equal parent based ' +
661
+ 'context (keys: %s) while mounting %s ' +
662
+ '(see: http://fb.me/react-context-by-parent)',
663
+ Object.keys(ownerBasedContext),
664
+ Object.keys(parentBasedContext),
665
+ displayName
666
+ ) : null);
667
+ } else {
668
+ for (var i = 0; i < parentKeys.length; i++) {
669
+ var key = parentKeys[i];
670
+ ("production" !== process.env.NODE_ENV ? warning(
671
+ ownerBasedContext[key] === parentBasedContext[key],
672
+ 'owner-based and parent-based contexts differ ' +
673
+ '(values: `%s` vs `%s`) for key (%s) while mounting %s ' +
674
+ '(see: http://fb.me/react-context-by-parent)',
675
+ ownerBasedContext[key],
676
+ parentBasedContext[key],
677
+ key,
678
+ displayName
679
+ ) : null);
680
+ }
681
+ }
682
+ },
683
+
684
+ /**
685
+ * Perform an update to a mounted component. The componentWillReceiveProps and
686
+ * shouldComponentUpdate methods are called, then (assuming the update isn't
687
+ * skipped) the remaining update lifecycle methods are called and the DOM
688
+ * representation is updated.
689
+ *
690
+ * By default, this implements React's rendering and reconciliation algorithm.
691
+ * Sophisticated clients may wish to override this.
692
+ *
693
+ * @param {ReactReconcileTransaction} transaction
694
+ * @param {ReactElement} prevParentElement
695
+ * @param {ReactElement} nextParentElement
696
+ * @internal
697
+ * @overridable
698
+ */
699
+ updateComponent: function(
700
+ transaction,
701
+ prevParentElement,
702
+ nextParentElement,
703
+ prevUnmaskedContext,
704
+ nextUnmaskedContext
705
+ ) {
706
+ // Update refs regardless of what shouldComponentUpdate returns
707
+ ReactComponent.Mixin.updateComponent.call(
708
+ this,
709
+ transaction,
710
+ prevParentElement,
711
+ nextParentElement,
712
+ prevUnmaskedContext,
713
+ nextUnmaskedContext
714
+ );
715
+
716
+ var inst = this._instance;
717
+
718
+ var prevContext = inst.context;
719
+ var prevProps = inst.props;
720
+ var nextContext = prevContext;
721
+ var nextProps = prevProps;
722
+ // Distinguish between a props update versus a simple state update
723
+ if (prevParentElement !== nextParentElement) {
724
+ nextContext = this._processContext(nextParentElement._context);
725
+ nextProps = this._processProps(nextParentElement.props);
726
+
727
+ if ("production" !== process.env.NODE_ENV) {
728
+ if (nextUnmaskedContext != null) {
729
+ this._warnIfContextsDiffer(nextParentElement._context, nextUnmaskedContext);
730
+ }
731
+ }
1044
732
 
1045
733
  this._compositeLifeCycleState = CompositeLifeCycle.RECEIVING_PROPS;
1046
- if (this.componentWillReceiveProps) {
1047
- this.componentWillReceiveProps(nextProps, nextContext);
734
+ if (inst.componentWillReceiveProps) {
735
+ inst.componentWillReceiveProps(nextProps, nextContext);
1048
736
  }
1049
737
  }
1050
738
 
1051
739
  this._compositeLifeCycleState = null;
1052
740
 
1053
- var nextState = this._pendingState || this.state;
741
+ var nextState = this._pendingState || inst.state;
1054
742
  this._pendingState = null;
1055
743
 
1056
744
  var shouldUpdate =
1057
745
  this._pendingForceUpdate ||
1058
- !this.shouldComponentUpdate ||
1059
- this.shouldComponentUpdate(nextProps, nextState, nextContext);
746
+ !inst.shouldComponentUpdate ||
747
+ inst.shouldComponentUpdate(nextProps, nextState, nextContext);
1060
748
 
1061
749
  if ("production" !== process.env.NODE_ENV) {
1062
- if (typeof shouldUpdate === "undefined") {
750
+ if (typeof shouldUpdate === 'undefined') {
1063
751
  console.warn(
1064
- (this.constructor.displayName || 'ReactCompositeComponent') +
752
+ (this.getName() || 'ReactCompositeComponent') +
1065
753
  '.shouldComponentUpdate(): Returned undefined instead of a ' +
1066
754
  'boolean value. Make sure to return true or false.'
1067
755
  );
1068
756
  }
1069
757
  }
1070
758
 
1071
- if (shouldUpdate) {
1072
- this._pendingForceUpdate = false;
1073
- // Will set `this.props`, `this.state` and `this.context`.
1074
- this._performComponentUpdate(
1075
- nextElement,
1076
- nextProps,
1077
- nextState,
1078
- nextContext,
1079
- transaction
1080
- );
1081
- } else {
759
+ if (!shouldUpdate) {
1082
760
  // 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;
761
+ // to set props and state but we shortcut the rest of the update.
762
+ this._currentElement = nextParentElement;
763
+ this._context = nextUnmaskedContext;
764
+ inst.props = nextProps;
765
+ inst.state = nextState;
766
+ inst.context = nextContext;
767
+ return;
1092
768
  }
769
+
770
+ this._pendingForceUpdate = false;
771
+ // Will set `this.props`, `this.state` and `this.context`.
772
+ this._performComponentUpdate(
773
+ nextParentElement,
774
+ nextProps,
775
+ nextState,
776
+ nextContext,
777
+ transaction,
778
+ nextUnmaskedContext
779
+ );
1093
780
  },
1094
781
 
1095
782
  /**
@@ -1101,6 +788,7 @@ var ReactCompositeComponentMixin = {
1101
788
  * @param {?object} nextState Next object to set as state.
1102
789
  * @param {?object} nextContext Next public object to set as context.
1103
790
  * @param {ReactReconcileTransaction} transaction
791
+ * @param {?object} unmaskedContext
1104
792
  * @private
1105
793
  */
1106
794
  _performComponentUpdate: function(
@@ -1108,329 +796,296 @@ var ReactCompositeComponentMixin = {
1108
796
  nextProps,
1109
797
  nextState,
1110
798
  nextContext,
1111
- transaction
799
+ transaction,
800
+ unmaskedContext
1112
801
  ) {
1113
- var prevElement = this._currentElement;
1114
- var prevProps = this.props;
1115
- var prevState = this.state;
1116
- var prevContext = this.context;
802
+ var inst = this._instance;
1117
803
 
1118
- if (this.componentWillUpdate) {
1119
- this.componentWillUpdate(nextProps, nextState, nextContext);
804
+ var prevProps = inst.props;
805
+ var prevState = inst.state;
806
+ var prevContext = inst.context;
807
+
808
+ if (inst.componentWillUpdate) {
809
+ inst.componentWillUpdate(nextProps, nextState, nextContext);
1120
810
  }
1121
811
 
1122
812
  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;
813
+ this._context = unmaskedContext;
814
+ inst.props = nextProps;
815
+ inst.state = nextState;
816
+ inst.context = nextContext;
1130
817
 
1131
- this.updateComponent(
1132
- transaction,
1133
- prevElement
1134
- );
818
+ this._updateRenderedComponent(transaction, unmaskedContext);
1135
819
 
1136
- if (this.componentDidUpdate) {
820
+ if (inst.componentDidUpdate) {
1137
821
  transaction.getReactMountReady().enqueue(
1138
- this.componentDidUpdate.bind(this, prevProps, prevState, prevContext),
1139
- this
822
+ inst.componentDidUpdate.bind(inst, prevProps, prevState, prevContext),
823
+ inst
1140
824
  );
1141
825
  }
1142
826
  },
1143
827
 
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
828
  /**
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.
829
+ * Call the component's `render` method and update the DOM accordingly.
1169
830
  *
1170
831
  * @param {ReactReconcileTransaction} transaction
1171
- * @param {ReactElement} prevElement
1172
832
  * @internal
1173
- * @overridable
1174
833
  */
1175
- updateComponent: ReactPerf.measure(
1176
- 'ReactCompositeComponent',
1177
- 'updateComponent',
1178
- function(transaction, prevParentElement) {
1179
- ReactComponent.Mixin.updateComponent.call(
1180
- this,
834
+ _updateRenderedComponent: function(transaction, context) {
835
+ var prevComponentInstance = this._renderedComponent;
836
+ var prevRenderedElement = prevComponentInstance._currentElement;
837
+ var nextRenderedElement = this._renderValidatedComponent();
838
+ if (shouldUpdateReactComponent(prevRenderedElement, nextRenderedElement)) {
839
+ prevComponentInstance.receiveComponent(
840
+ nextRenderedElement,
1181
841
  transaction,
1182
- prevParentElement
842
+ this._processChildContext(context)
843
+ );
844
+ } else {
845
+ // These two IDs are actually the same! But nothing should rely on that.
846
+ var thisID = this._rootNodeID;
847
+ var prevComponentID = prevComponentInstance._rootNodeID;
848
+ prevComponentInstance.unmountComponent();
849
+
850
+ this._renderedComponent = this._instantiateReactComponent(
851
+ nextRenderedElement,
852
+ this._currentElement.type
853
+ );
854
+ var nextMarkup = this._renderedComponent.mountComponent(
855
+ thisID,
856
+ transaction,
857
+ context
858
+ );
859
+ ReactComponentEnvironment.replaceNodeWithMarkupByID(
860
+ prevComponentID,
861
+ nextMarkup
1183
862
  );
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
- }
1209
863
  }
1210
- ),
864
+ },
1211
865
 
1212
866
  /**
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
- * @protected
867
+ * @private
1225
868
  */
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);
869
+ _renderValidatedComponentWithoutOwnerOrContext: function() {
870
+ var inst = this._instance;
871
+ var renderedComponent = inst.render();
872
+ if ("production" !== process.env.NODE_ENV) {
873
+ // We allow auto-mocks to proceed as if they're returning null.
874
+ if (typeof renderedComponent === 'undefined' &&
875
+ inst.render._isMockFunction) {
876
+ // This is probably bad practice. Consider warning here and
877
+ // deprecating this convenience.
878
+ renderedComponent = null;
879
+ }
880
+ }
881
+
882
+ return renderedComponent;
1244
883
  },
1245
884
 
1246
885
  /**
1247
886
  * @private
1248
887
  */
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;
1270
- }
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;
888
+ _renderValidatedComponent: function() {
889
+ var renderedComponent;
890
+ var previousContext = ReactContext.current;
891
+ ReactContext.current = this._processChildContext(
892
+ this._currentElement._context
893
+ );
894
+ ReactCurrentOwner.current = this;
895
+ var inst = this._instance;
896
+ try {
897
+ renderedComponent =
898
+ this._renderValidatedComponentWithoutOwnerOrContext();
899
+ } finally {
900
+ ReactContext.current = previousContext;
901
+ ReactCurrentOwner.current = null;
1278
902
  }
1279
- ),
903
+ ("production" !== process.env.NODE_ENV ? invariant(
904
+ // TODO: An `isValidNode` function would probably be more appropriate
905
+ renderedComponent === null || renderedComponent === false ||
906
+ ReactElement.isValidElement(renderedComponent),
907
+ '%s.render(): A valid ReactComponent must be returned. You may have ' +
908
+ 'returned undefined, an array or some other invalid object.',
909
+ this.getName() || 'ReactCompositeComponent'
910
+ ) : invariant(// TODO: An `isValidNode` function would probably be more appropriate
911
+ renderedComponent === null || renderedComponent === false ||
912
+ ReactElement.isValidElement(renderedComponent)));
913
+ return renderedComponent;
914
+ },
1280
915
 
1281
916
  /**
917
+ * Lazily allocates the refs object and stores `component` as `ref`.
918
+ *
919
+ * @param {string} ref Reference name.
920
+ * @param {component} component Component to store as `ref`.
921
+ * @final
1282
922
  * @private
1283
923
  */
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
- ));
1294
- }
924
+ attachRef: function(ref, component) {
925
+ var inst = this.getPublicInstance();
926
+ var refs = inst.refs === emptyObject ? (inst.refs = {}) : inst.refs;
927
+ refs[ref] = component.getPublicInstance();
1295
928
  },
1296
929
 
1297
930
  /**
1298
- * Binds a method to the component.
931
+ * Detaches a reference name.
1299
932
  *
1300
- * @param {function} method Method to be bound.
933
+ * @param {string} ref Name to dereference.
934
+ * @final
1301
935
  * @private
1302
936
  */
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 ) {var args=Array.prototype.slice.call(arguments,1);
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
- };
937
+ detachRef: function(ref) {
938
+ var refs = this.getPublicInstance().refs;
939
+ delete refs[ref];
940
+ },
1341
941
 
1342
- var ReactCompositeComponentBase = function() {};
1343
- assign(
1344
- ReactCompositeComponentBase.prototype,
1345
- ReactComponent.Mixin,
1346
- ReactOwner.Mixin,
1347
- ReactPropTransferer.Mixin,
1348
- ReactCompositeComponentMixin
1349
- );
942
+ /**
943
+ * Get a text description of the component that can be used to identify it
944
+ * in error messages.
945
+ * @return {string} The name or null.
946
+ * @internal
947
+ */
948
+ getName: function() {
949
+ var type = this._currentElement.type;
950
+ var constructor = this._instance.constructor;
951
+ return (
952
+ type.displayName || (constructor && constructor.displayName) ||
953
+ type.name || (constructor && constructor.name) ||
954
+ null
955
+ );
956
+ },
1350
957
 
1351
- /**
1352
- * Module for creating composite components.
1353
- *
1354
- * @class ReactCompositeComponent
1355
- * @extends ReactComponent
1356
- * @extends ReactOwner
1357
- * @extends ReactPropTransferer
1358
- */
1359
- var ReactCompositeComponent = {
958
+ /**
959
+ * Get the publicly accessible representation of this component - i.e. what
960
+ * is exposed by refs and returned by React.render. Can be null for stateless
961
+ * components.
962
+ *
963
+ * @return {ReactComponent} the public component instance.
964
+ * @internal
965
+ */
966
+ getPublicInstance: function() {
967
+ return this._instance;
968
+ },
1360
969
 
1361
- LifeCycle: CompositeLifeCycle,
970
+ // Stub
971
+ _instantiateReactComponent: null
972
+
973
+ });
1362
974
 
1363
- Base: ReactCompositeComponentBase,
975
+ var ShallowMixin = assign({},
976
+ ReactCompositeComponentMixin, {
1364
977
 
1365
978
  /**
1366
- * Creates a composite component class given a class specification.
979
+ * Initializes the component, renders markup, and registers event listeners.
1367
980
  *
1368
- * @param {object} spec Class specification (which must define `render`).
1369
- * @return {function} Component constructor function.
1370
- * @public
981
+ * @param {string} rootID DOM ID of the root node.
982
+ * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
983
+ * @return {ReactElement} Shallow rendering of the component.
984
+ * @final
985
+ * @internal
1371
986
  */
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)
987
+ mountComponent: function(rootID, transaction, context) {
988
+ ReactComponent.Mixin.mountComponent.call(
989
+ this,
990
+ rootID,
991
+ transaction,
992
+ context
1383
993
  );
1384
994
 
1385
- mixSpecIntoComponent(Constructor, spec);
995
+ var inst = this._instance;
1386
996
 
1387
- // Initialize the defaultProps property after all mixins have been merged
1388
- if (Constructor.getDefaultProps) {
1389
- Constructor.defaultProps = Constructor.getDefaultProps();
1390
- }
997
+ // Store a reference from the instance back to the internal representation
998
+ ReactInstanceMap.set(inst, this);
1391
999
 
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));
1000
+ this._compositeLifeCycleState = CompositeLifeCycle.MOUNTING;
1001
+
1002
+ // No context for shallow-mounted components.
1003
+ inst.props = this._processProps(this._currentElement.props);
1396
1004
 
1005
+ var initialState = inst.getInitialState ? inst.getInitialState() : null;
1397
1006
  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
- );
1007
+ // We allow auto-mocks to proceed as if they're returning null.
1008
+ if (typeof initialState === 'undefined' &&
1009
+ inst.getInitialState._isMockFunction) {
1010
+ // This is probably bad practice. Consider warning here and
1011
+ // deprecating this convenience.
1012
+ initialState = null;
1409
1013
  }
1410
1014
  }
1015
+ ("production" !== process.env.NODE_ENV ? invariant(
1016
+ typeof initialState === 'object' && !Array.isArray(initialState),
1017
+ '%s.getInitialState(): must return an object or null',
1018
+ this.getName() || 'ReactCompositeComponent'
1019
+ ) : invariant(typeof initialState === 'object' && !Array.isArray(initialState)));
1020
+ inst.state = initialState;
1411
1021
 
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;
1022
+ this._pendingState = null;
1023
+ this._pendingForceUpdate = false;
1024
+
1025
+ if (inst.componentWillMount) {
1026
+ inst.componentWillMount();
1027
+ // When mounting, calls to `setState` by `componentWillMount` will set
1028
+ // `this._pendingState` without triggering a re-render.
1029
+ if (this._pendingState) {
1030
+ inst.state = this._pendingState;
1031
+ this._pendingState = null;
1416
1032
  }
1417
1033
  }
1418
1034
 
1419
- if ("production" !== process.env.NODE_ENV) {
1420
- return ReactLegacyElement.wrapFactory(
1421
- ReactElementValidator.createFactory(Constructor)
1422
- );
1035
+ // No recursive call to instantiateReactComponent for shallow rendering.
1036
+ this._renderedComponent =
1037
+ this._renderValidatedComponentWithoutOwnerOrContext();
1038
+
1039
+ // Done with mounting, `setState` will now trigger UI changes.
1040
+ this._compositeLifeCycleState = null;
1041
+
1042
+ // No call to this._renderedComponent.mountComponent for shallow
1043
+ // rendering.
1044
+
1045
+ if (inst.componentDidMount) {
1046
+ transaction.getReactMountReady().enqueue(inst.componentDidMount, inst);
1423
1047
  }
1424
- return ReactLegacyElement.wrapFactory(
1425
- ReactElement.createFactory(Constructor)
1426
- );
1048
+
1049
+ return this._renderedComponent;
1427
1050
  },
1428
1051
 
1429
- injection: {
1430
- injectMixin: function(mixin) {
1431
- injectedMixins.push(mixin);
1432
- }
1052
+ /**
1053
+ * Call the component's `render` method and update the DOM accordingly.
1054
+ *
1055
+ * @param {ReactReconcileTransaction} transaction
1056
+ * @internal
1057
+ */
1058
+ _updateRenderedComponent: function(transaction) {
1059
+ var prevComponentInstance = this._renderedComponent;
1060
+ var prevRenderedElement = prevComponentInstance._currentElement;
1061
+ // Use the without-owner-or-context variant of _rVC below:
1062
+ var nextRenderedElement =
1063
+ this._renderValidatedComponentWithoutOwnerOrContext();
1064
+ // This is a noop in shallow render
1065
+ shouldUpdateReactComponent(prevRenderedElement, nextRenderedElement);
1066
+ this._renderedComponent = nextRenderedElement;
1067
+ }
1068
+
1069
+ });
1070
+
1071
+ ReactPerf.measureMethods(
1072
+ ReactCompositeComponentMixin,
1073
+ 'ReactCompositeComponent',
1074
+ {
1075
+ mountComponent: 'mountComponent',
1076
+ updateComponent: 'updateComponent',
1077
+ _renderValidatedComponent: '_renderValidatedComponent'
1433
1078
  }
1079
+ );
1080
+
1081
+ var ReactCompositeComponent = {
1082
+
1083
+ LifeCycle: CompositeLifeCycle,
1084
+
1085
+ Mixin: ReactCompositeComponentMixin,
1086
+
1087
+ ShallowMixin: ShallowMixin
1088
+
1434
1089
  };
1435
1090
 
1436
1091
  module.exports = ReactCompositeComponent;