react 0.13.0-alpha.1 → 0.13.0-rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (182) hide show
  1. package/dist/JSXTransformer.js +1376 -596
  2. package/dist/react-with-addons.js +3256 -2363
  3. package/dist/react-with-addons.min.js +7 -7
  4. package/dist/react.js +3092 -2266
  5. package/dist/react.min.js +6 -7
  6. package/lib/AutoFocusMixin.js +2 -2
  7. package/lib/BeforeInputEventPlugin.js +5 -9
  8. package/lib/CSSCore.js +1 -1
  9. package/lib/CSSProperty.js +4 -2
  10. package/lib/CSSPropertyOperations.js +44 -17
  11. package/lib/CallbackQueue.js +3 -3
  12. package/lib/ChangeEventPlugin.js +2 -2
  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 +7 -6
  18. package/lib/DefaultEventPluginOrder.js +3 -3
  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 +1 -1
  27. package/lib/FallbackCompositionState.js +7 -5
  28. package/lib/HTMLDOMPropertyConfig.js +22 -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 +2 -2
  34. package/lib/PooledClass.js +2 -2
  35. package/lib/React.js +9 -13
  36. package/lib/ReactBrowserComponentMixin.js +2 -2
  37. package/lib/ReactBrowserEventEmitter.js +4 -4
  38. package/lib/ReactCSSTransitionGroup.js +2 -2
  39. package/lib/ReactCSSTransitionGroupChild.js +12 -7
  40. package/lib/ReactChildReconciler.js +11 -7
  41. package/lib/ReactChildren.js +13 -10
  42. package/lib/ReactClass.js +161 -135
  43. package/lib/ReactComponent.js +100 -158
  44. package/lib/ReactComponentBrowserEnvironment.js +2 -2
  45. package/lib/ReactComponentEnvironment.js +3 -3
  46. package/lib/ReactComponentWithPureRenderMixin.js +2 -2
  47. package/lib/ReactCompositeComponent.js +336 -484
  48. package/lib/ReactContext.js +14 -4
  49. package/lib/ReactCurrentOwner.js +2 -2
  50. package/lib/ReactDOM.js +2 -2
  51. package/lib/ReactDOMButton.js +2 -2
  52. package/lib/ReactDOMComponent.js +42 -52
  53. package/lib/ReactDOMForm.js +2 -2
  54. package/lib/ReactDOMIDOperations.js +4 -4
  55. package/lib/ReactDOMIframe.js +43 -0
  56. package/lib/ReactDOMImg.js +2 -2
  57. package/lib/ReactDOMInput.js +2 -2
  58. package/lib/ReactDOMOption.js +2 -2
  59. package/lib/ReactDOMSelect.js +3 -3
  60. package/lib/ReactDOMSelection.js +2 -2
  61. package/lib/ReactDOMTextComponent.js +4 -13
  62. package/lib/ReactDOMTextarea.js +2 -2
  63. package/lib/ReactDefaultBatchingStrategy.js +5 -5
  64. package/lib/ReactDefaultInjection.js +26 -2
  65. package/lib/ReactDefaultPerf.js +12 -4
  66. package/lib/ReactDefaultPerfAnalysis.js +1 -1
  67. package/lib/ReactElement.js +7 -5
  68. package/lib/ReactElementValidator.js +185 -65
  69. package/lib/ReactEmptyComponent.js +17 -6
  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 +180 -0
  74. package/lib/ReactInjection.js +2 -2
  75. package/lib/ReactInputSelection.js +2 -2
  76. package/lib/ReactInstanceHandles.js +4 -3
  77. package/lib/ReactInstanceMap.js +2 -2
  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 +87 -23
  82. package/lib/ReactMultiChild.js +19 -7
  83. package/lib/ReactMultiChildUpdateTypes.js +2 -2
  84. package/lib/ReactNativeComponent.js +34 -37
  85. package/lib/ReactOwner.js +2 -2
  86. package/lib/ReactPerf.js +2 -2
  87. package/lib/ReactPropTransferer.js +3 -3
  88. package/lib/ReactPropTypeLocationNames.js +2 -2
  89. package/lib/ReactPropTypeLocations.js +2 -2
  90. package/lib/ReactPropTypes.js +16 -8
  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 +41 -68
  95. package/lib/ReactRootIndex.js +2 -2
  96. package/lib/ReactServerRendering.js +4 -3
  97. package/lib/ReactServerRenderingTransaction.js +2 -2
  98. package/lib/ReactStateSetters.js +2 -2
  99. package/lib/ReactTestUtils.js +49 -8
  100. package/lib/ReactTransitionChildMapping.js +8 -4
  101. package/lib/ReactTransitionEvents.js +2 -2
  102. package/lib/ReactTransitionGroup.js +6 -6
  103. package/lib/ReactUpdateQueue.js +295 -0
  104. package/lib/ReactUpdates.js +13 -22
  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 +2 -2
  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 +5 -5
  122. package/lib/ViewportMetrics.js +2 -2
  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 +2 -2
  131. package/lib/createNodesFromMarkup.js +4 -4
  132. package/lib/cx.js +16 -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 +26 -9
  138. package/lib/flattenChildren.js +11 -9
  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 +2 -2
  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 +21 -21
  155. package/lib/invariant.js +1 -1
  156. package/lib/isEventSupported.js +2 -2
  157. package/lib/isNode.js +1 -1
  158. package/lib/isTextInputElement.js +2 -2
  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 +64 -8
  173. package/lib/toArray.js +2 -2
  174. package/lib/traverseAllChildren.js +19 -5
  175. package/lib/update.js +2 -2
  176. package/lib/warning.js +20 -2
  177. package/package.json +1 -1
  178. package/lib/accumulate.js +0 -47
  179. package/lib/copyProperties.js +0 -56
  180. package/lib/merge.js +0 -34
  181. package/lib/mergeInto.js +0 -24
  182. 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
@@ -9,181 +9,123 @@
9
9
  * @providesModule ReactComponent
10
10
  */
11
11
 
12
- "use strict";
12
+ 'use strict';
13
13
 
14
- var ReactOwner = require("./ReactOwner");
15
- var ReactRef = require("./ReactRef");
14
+ var ReactUpdateQueue = require("./ReactUpdateQueue");
16
15
 
17
16
  var invariant = require("./invariant");
17
+ var warning = require("./warning");
18
18
 
19
- function attachRef(ref, component, owner) {
20
- if (ref instanceof ReactRef) {
21
- ReactRef.attachRef(ref, component);
22
- } else {
23
- ReactOwner.addComponentAsRefTo(component, ref, owner);
24
- }
25
- }
26
-
27
- function detachRef(ref, component, owner) {
28
- if (ref instanceof ReactRef) {
29
- ReactRef.detachRef(ref, component);
30
- } else {
31
- ReactOwner.removeComponentAsRefFrom(component, ref, owner);
32
- }
19
+ /**
20
+ * Base class helpers for the updating state of a component.
21
+ */
22
+ function ReactComponent(props, context) {
23
+ this.props = props;
24
+ this.context = context;
33
25
  }
34
26
 
35
27
  /**
36
- * Components are the basic units of composition in React.
28
+ * Sets a subset of the state. Always use this to mutate
29
+ * state. You should treat `this.state` as immutable.
37
30
  *
38
- * Every component accepts a set of keyed input parameters known as "props" that
39
- * are initialized by the constructor. Once a component is mounted, the props
40
- * can be mutated using `setProps` or `replaceProps`.
31
+ * There is no guarantee that `this.state` will be immediately updated, so
32
+ * accessing `this.state` after calling this method may return the old value.
41
33
  *
42
- * Every component is capable of the following operations:
34
+ * There is no guarantee that calls to `setState` will run synchronously,
35
+ * as they may eventually be batched together. You can provide an optional
36
+ * callback that will be executed when the call to setState is actually
37
+ * completed.
43
38
  *
44
- * `mountComponent`
45
- * Initializes the component, renders markup, and registers event listeners.
39
+ * When a function is provided to setState, it will be called at some point in
40
+ * the future (not synchronously). It will be called with the up to date
41
+ * component arguments (state, props, context). These values can be different
42
+ * from this.* because your function may be called after receiveProps but before
43
+ * shouldComponentUpdate, and this new state, props, and context will not yet be
44
+ * assigned to this.
46
45
  *
47
- * `receiveComponent`
48
- * Updates the rendered DOM nodes to match the given component.
46
+ * @param {object|function} partialState Next partial state or function to
47
+ * produce next partial state to be merged with current state.
48
+ * @param {?function} callback Called after state is updated.
49
+ * @final
50
+ * @protected
51
+ */
52
+ ReactComponent.prototype.setState = function(partialState, callback) {
53
+ ("production" !== process.env.NODE_ENV ? invariant(
54
+ typeof partialState === 'object' ||
55
+ typeof partialState === 'function' ||
56
+ partialState == null,
57
+ 'setState(...): takes an object of state variables to update or a ' +
58
+ 'function which returns an object of state variables.'
59
+ ) : invariant(typeof partialState === 'object' ||
60
+ typeof partialState === 'function' ||
61
+ partialState == null));
62
+ if ("production" !== process.env.NODE_ENV) {
63
+ ("production" !== process.env.NODE_ENV ? warning(
64
+ partialState != null,
65
+ 'setState(...): You passed an undefined or null state object; ' +
66
+ 'instead, use forceUpdate().'
67
+ ) : null);
68
+ }
69
+ ReactUpdateQueue.enqueueSetState(this, partialState);
70
+ if (callback) {
71
+ ReactUpdateQueue.enqueueCallback(this, callback);
72
+ }
73
+ };
74
+
75
+ /**
76
+ * Forces an update. This should only be invoked when it is known with
77
+ * certainty that we are **not** in a DOM transaction.
49
78
  *
50
- * `unmountComponent`
51
- * Releases any resources allocated by this component.
79
+ * You may want to call this when you know that some deeper aspect of the
80
+ * component's state has changed but `setState` was not called.
52
81
  *
53
- * Components can also be "owned" by other components. Being owned by another
54
- * component means being constructed by that component. This is different from
55
- * being the child of a component, which means having a DOM representation that
56
- * is a child of the DOM representation of that component.
82
+ * This will not invoke `shouldUpdateComponent`, but it will invoke
83
+ * `componentWillUpdate` and `componentDidUpdate`.
57
84
  *
58
- * @class ReactComponent
85
+ * @param {?function} callback Called after update is complete.
86
+ * @final
87
+ * @protected
59
88
  */
60
- var ReactComponent = {
61
-
62
- /**
63
- * Injected module that provides ability to mutate individual properties.
64
- * Injected into the base class because many different subclasses need access
65
- * to this.
66
- *
67
- * @internal
68
- */
69
- BackendIDOperations: null,
70
-
71
- /**
72
- * Base functionality for every ReactComponent constructor. Mixed into the
73
- * `ReactComponent` prototype, but exposed statically for easy access.
74
- *
75
- * @lends {ReactComponent.prototype}
76
- */
77
- Mixin: {
78
-
79
- /**
80
- * Base constructor for all React components.
81
- *
82
- * Subclasses that override this method should make sure to invoke
83
- * `ReactComponent.Mixin.construct.call(this, ...)`.
84
- *
85
- * @param {ReactElement} element
86
- * @internal
87
- */
88
- construct: function(element) {
89
- // We keep the old element and a reference to the pending element
90
- // to track updates.
91
- this._currentElement = element;
92
- // These two fields are used by the DOM and ART diffing algorithms
93
- // respectively. Instead of using expandos on components, we should be
94
- // storing the state needed by the diffing algorithms elsewhere.
95
- this._mountIndex = 0;
96
- this._mountImage = null;
97
- },
98
-
99
- /**
100
- * Initializes the component, renders markup, and registers event listeners.
101
- *
102
- * NOTE: This does not insert any nodes into the DOM.
103
- *
104
- * Subclasses that override this method should make sure to invoke
105
- * `ReactComponent.Mixin.mountComponent.call(this, ...)`.
106
- *
107
- * @param {string} rootID DOM ID of the root node.
108
- * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
109
- * @return {?string} Rendered markup to be inserted into the DOM.
110
- * @internal
111
- */
112
- mountComponent: function(rootID, transaction, context) {
113
- var ref = this._currentElement.ref;
114
- if (ref != null) {
115
- var owner = this._currentElement._owner;
116
- attachRef(ref, this, owner);
117
- }
118
- // Effectively: return '';
119
- },
120
-
121
- /**
122
- * Releases any resources allocated by `mountComponent`.
123
- *
124
- * NOTE: This does not remove any nodes from the DOM.
125
- *
126
- * Subclasses that override this method should make sure to invoke
127
- * `ReactComponent.Mixin.unmountComponent.call(this)`.
128
- *
129
- * @internal
130
- */
131
- unmountComponent: function() {
132
- var ref = this._currentElement.ref;
133
- if (ref != null) {
134
- detachRef(ref, this, this._currentElement._owner);
135
- }
136
- },
137
-
138
- /**
139
- * Updates the component's currently mounted representation.
140
- *
141
- * @param {ReactReconcileTransaction} transaction
142
- * @param {object} prevElement
143
- * @param {object} nextElement
144
- * @internal
145
- */
146
- updateComponent: function(transaction, prevElement, nextElement, context) {
147
- // If either the owner or a `ref` has changed, make sure the newest owner
148
- // has stored a reference to `this`, and the previous owner (if different)
149
- // has forgotten the reference to `this`. We use the element instead
150
- // of the public this.props because the post processing cannot determine
151
- // a ref. The ref conceptually lives on the element.
152
-
153
- // TODO: Should this even be possible? The owner cannot change because
154
- // it's forbidden by shouldUpdateReactComponent. The ref can change
155
- // if you swap the keys of but not the refs. Reconsider where this check
156
- // is made. It probably belongs where the key checking and
157
- // instantiateReactComponent is done.
89
+ ReactComponent.prototype.forceUpdate = function(callback) {
90
+ ReactUpdateQueue.enqueueForceUpdate(this);
91
+ if (callback) {
92
+ ReactUpdateQueue.enqueueCallback(this, callback);
93
+ }
94
+ };
158
95
 
159
- if (nextElement._owner !== prevElement._owner ||
160
- nextElement.ref !== prevElement.ref) {
161
- if (prevElement.ref != null) {
162
- detachRef(prevElement.ref, this, prevElement._owner);
163
- }
164
- // Correct, even if the owner is the same, and only the ref has changed.
165
- if (nextElement.ref != null) {
166
- attachRef(nextElement.ref, this, nextElement._owner);
96
+ /**
97
+ * Deprecated APIs. These APIs used to exist on classic React classes but since
98
+ * we would like to deprecate them, we're not going to move them over to this
99
+ * modern base class. Instead, we define a getter that warns if it's accessed.
100
+ */
101
+ if ("production" !== process.env.NODE_ENV) {
102
+ var deprecatedAPIs = {
103
+ getDOMNode: 'getDOMNode',
104
+ isMounted: 'isMounted',
105
+ replaceState: 'replaceState',
106
+ setProps: 'setProps'
107
+ };
108
+ var defineDeprecationWarning = function(methodName, displayName) {
109
+ try {
110
+ Object.defineProperty(ReactComponent.prototype, methodName, {
111
+ get: function() {
112
+ ("production" !== process.env.NODE_ENV ? warning(
113
+ false,
114
+ '%s(...) is deprecated in plain JavaScript React classes.',
115
+ displayName
116
+ ) : null);
117
+ return undefined;
167
118
  }
168
- }
169
- },
170
-
171
- /**
172
- * Get the publicly accessible representation of this component - i.e. what
173
- * is exposed by refs and returned by React.render. Can be null for
174
- * stateless components.
175
- *
176
- * @return {?ReactComponent} the actual sibling Component.
177
- * @internal
178
- */
179
- getPublicInstance: function() {
180
- ("production" !== process.env.NODE_ENV ? invariant(
181
- false,
182
- 'getPublicInstance should never be called on the base class. It must ' +
183
- 'be overridden.'
184
- ) : invariant(false));
119
+ });
120
+ } catch (x) {
121
+ // IE will fail on defineProperty (es5-shim/sham too)
122
+ }
123
+ };
124
+ for (var fnName in deprecatedAPIs) {
125
+ if (deprecatedAPIs.hasOwnProperty(fnName)) {
126
+ defineDeprecationWarning(fnName, deprecatedAPIs[fnName]);
185
127
  }
186
128
  }
187
- };
129
+ }
188
130
 
189
131
  module.exports = ReactComponent;
@@ -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,7 +11,7 @@
11
11
 
12
12
  /*jslint evil: true */
13
13
 
14
- "use strict";
14
+ 'use strict';
15
15
 
16
16
  var ReactDOMIDOperations = require("./ReactDOMIDOperations");
17
17
  var ReactMount = require("./ReactMount");
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Copyright 2014, Facebook, Inc.
2
+ * Copyright 2014-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 ReactComponentEnvironment
10
10
  */
11
11
 
12
- "use strict";
12
+ 'use strict';
13
13
 
14
14
  var invariant = require("./invariant");
15
15
 
@@ -50,7 +50,7 @@ var ReactComponentEnvironment = {
50
50
  environment.processChildrenUpdates;
51
51
  injected = true;
52
52
  }
53
- },
53
+ }
54
54
 
55
55
  };
56
56
 
@@ -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,30 +9,32 @@
9
9
  * @providesModule ReactCompositeComponent
10
10
  */
11
11
 
12
- "use strict";
12
+ 'use strict';
13
13
 
14
- var ReactComponent = require("./ReactComponent");
15
14
  var ReactComponentEnvironment = require("./ReactComponentEnvironment");
16
15
  var ReactContext = require("./ReactContext");
17
16
  var ReactCurrentOwner = require("./ReactCurrentOwner");
18
17
  var ReactElement = require("./ReactElement");
18
+ var ReactElementValidator = require("./ReactElementValidator");
19
19
  var ReactInstanceMap = require("./ReactInstanceMap");
20
+ var ReactLifeCycle = require("./ReactLifeCycle");
21
+ var ReactNativeComponent = require("./ReactNativeComponent");
20
22
  var ReactPerf = require("./ReactPerf");
21
23
  var ReactPropTypeLocations = require("./ReactPropTypeLocations");
24
+ var ReactPropTypeLocationNames = require("./ReactPropTypeLocationNames");
25
+ var ReactReconciler = require("./ReactReconciler");
22
26
  var ReactUpdates = require("./ReactUpdates");
23
27
 
24
28
  var assign = require("./Object.assign");
25
29
  var emptyObject = require("./emptyObject");
26
30
  var invariant = require("./invariant");
27
- var keyMirror = require("./keyMirror");
28
31
  var shouldUpdateReactComponent = require("./shouldUpdateReactComponent");
29
32
  var warning = require("./warning");
30
33
 
31
34
  function getDeclarationErrorAddendum(component) {
32
35
  var owner = component._currentElement._owner || null;
33
36
  if (owner) {
34
- var constructor = owner._instance.constructor;
35
- var name = constructor && (constructor.displayName || constructor.name);
37
+ var name = owner.getName();
36
38
  if (name) {
37
39
  return ' Check the render method of `' + name + '`.';
38
40
  }
@@ -40,63 +42,32 @@ function getDeclarationErrorAddendum(component) {
40
42
  return '';
41
43
  }
42
44
 
43
- function validateLifeCycleOnReplaceState(instance) {
44
- var compositeLifeCycleState = instance._compositeLifeCycleState;
45
- ("production" !== process.env.NODE_ENV ? invariant(
46
- ReactCurrentOwner.current == null,
47
- 'replaceState(...): Cannot update during an existing state transition ' +
48
- '(such as within `render`). Render methods should be a pure function ' +
49
- 'of props and state.'
50
- ) : invariant(ReactCurrentOwner.current == null));
51
- ("production" !== process.env.NODE_ENV ? invariant(compositeLifeCycleState !== CompositeLifeCycle.UNMOUNTING,
52
- 'replaceState(...): Cannot update while unmounting component. This ' +
53
- 'usually means you called setState() on an unmounted component.'
54
- ) : invariant(compositeLifeCycleState !== CompositeLifeCycle.UNMOUNTING));
55
- }
56
-
57
45
  /**
58
- * `ReactCompositeComponent` maintains an auxiliary life cycle state in
59
- * `this._compositeLifeCycleState` (which can be null).
46
+ * ------------------ The Life-Cycle of a Composite Component ------------------
47
+ *
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
60
55
  *
61
- * This is different from the life cycle state maintained by `ReactComponent`.
62
- * The following diagram shows how the states overlap in
63
- * time. There are times when the CompositeLifeCycle is null - at those times it
64
- * is only meaningful to look at ComponentLifeCycle alone.
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
65
63
  *
66
- * Top Row: ReactComponent.ComponentLifeCycle
67
- * Low Row: ReactComponent.CompositeLifeCycle
64
+ * - componentWillUnmount
65
+ * - [children's componentWillUnmount]
66
+ * - [children destroyed]
67
+ * - (destroyed): The instance is now blank, released by React and ready for GC.
68
68
  *
69
- * +-------+---------------------------------+--------+
70
- * | UN | MOUNTED | UN |
71
- * |MOUNTED| | MOUNTED|
72
- * +-------+---------------------------------+--------+
73
- * | ^--------+ +-------+ +--------^ |
74
- * | | | | | | | |
75
- * | 0--|MOUNTING|-0-|RECEIVE|-0-| UN |--->0 |
76
- * | | | |PROPS | |MOUNTING| |
77
- * | | | | | | | |
78
- * | | | | | | | |
79
- * | +--------+ +-------+ +--------+ |
80
- * | | | |
81
- * +-------+---------------------------------+--------+
69
+ * -----------------------------------------------------------------------------
82
70
  */
83
- var CompositeLifeCycle = keyMirror({
84
- /**
85
- * Components in the process of being mounted respond to state changes
86
- * differently.
87
- */
88
- MOUNTING: null,
89
- /**
90
- * Components in the process of being unmounted are guarded against state
91
- * changes.
92
- */
93
- UNMOUNTING: null,
94
- /**
95
- * Components that are mounted and receiving new props respond to state
96
- * changes differently.
97
- */
98
- RECEIVING_PROPS: null
99
- });
100
71
 
101
72
  /**
102
73
  * An incrementing ID assigned to each component when it is mounted. This is
@@ -109,8 +80,7 @@ var nextMountID = 1;
109
80
  /**
110
81
  * @lends {ReactCompositeComponent.prototype}
111
82
  */
112
- var ReactCompositeComponentMixin = assign({},
113
- ReactComponent.Mixin, {
83
+ var ReactCompositeComponentMixin = {
114
84
 
115
85
  /**
116
86
  * Base constructor for all composite component.
@@ -120,42 +90,26 @@ var ReactCompositeComponentMixin = assign({},
120
90
  * @internal
121
91
  */
122
92
  construct: function(element) {
93
+ this._currentElement = element;
123
94
  this._rootNodeID = null;
95
+ this._instance = null;
124
96
 
125
- this._instance.props = element.props;
126
- this._instance.state = null;
127
- this._instance.context = null;
128
- this._instance.refs = emptyObject;
129
-
97
+ // See ReactUpdateQueue
130
98
  this._pendingElement = null;
131
- this._pendingContext = null;
132
- this._pendingState = null;
99
+ this._pendingStateQueue = null;
100
+ this._pendingReplaceState = false;
133
101
  this._pendingForceUpdate = false;
134
- this._compositeLifeCycleState = null;
135
102
 
136
103
  this._renderedComponent = null;
137
104
 
138
- // Children can be either an array or more than one argument
139
- ReactComponent.Mixin.construct.apply(this, arguments);
140
-
141
105
  this._context = null;
142
106
  this._mountOrder = 0;
143
107
  this._isTopLevel = false;
144
108
 
145
- // See ReactUpdates.
109
+ // See ReactUpdates and ReactUpdateQueue.
146
110
  this._pendingCallbacks = null;
147
111
  },
148
112
 
149
- /**
150
- * Checks whether or not this composite component is mounted.
151
- * @return {boolean} True if mounted, false otherwise.
152
- * @protected
153
- * @final
154
- */
155
- isMounted: function() {
156
- return this._compositeLifeCycleState !== CompositeLifeCycle.MOUNTING;
157
- },
158
-
159
113
  /**
160
114
  * Initializes the component, renders markup, and registers event listeners.
161
115
  *
@@ -166,69 +120,108 @@ var ReactCompositeComponentMixin = assign({},
166
120
  * @internal
167
121
  */
168
122
  mountComponent: function(rootID, transaction, context) {
169
- ReactComponent.Mixin.mountComponent.call(
170
- this,
171
- rootID,
172
- transaction,
173
- context
174
- );
175
-
176
123
  this._context = context;
177
124
  this._mountOrder = nextMountID++;
178
125
  this._rootNodeID = rootID;
179
126
 
180
- var inst = this._instance;
127
+ var publicProps = this._processProps(this._currentElement.props);
128
+ var publicContext = this._processContext(this._currentElement._context);
129
+
130
+ var Component = ReactNativeComponent.getComponentClassForElement(
131
+ this._currentElement
132
+ );
133
+
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;
141
+
142
+ this._instance = inst;
181
143
 
182
144
  // Store a reference from the instance back to the internal representation
183
145
  ReactInstanceMap.set(inst, this);
184
146
 
185
- this._compositeLifeCycleState = CompositeLifeCycle.MOUNTING;
186
-
187
- inst.context = this._processContext(this._currentElement._context);
188
147
  if ("production" !== process.env.NODE_ENV) {
189
148
  this._warnIfContextsDiffer(this._currentElement._context, context);
190
149
  }
191
- inst.props = this._processProps(this._currentElement.props);
192
150
 
193
- var initialState = inst.getInitialState ? inst.getInitialState() : null;
194
151
  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
- }
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;
202
188
  }
203
189
  ("production" !== process.env.NODE_ENV ? invariant(
204
190
  typeof initialState === 'object' && !Array.isArray(initialState),
205
- '%s.getInitialState(): must return an object or null',
206
- inst.constructor.displayName || 'ReactCompositeComponent'
191
+ '%s.state: must be set to an object or null',
192
+ this.getName() || 'ReactCompositeComponent'
207
193
  ) : invariant(typeof initialState === 'object' && !Array.isArray(initialState)));
208
- inst.state = initialState;
209
194
 
210
- this._pendingState = null;
195
+ this._pendingStateQueue = null;
196
+ this._pendingReplaceState = false;
211
197
  this._pendingForceUpdate = false;
212
198
 
213
- if (inst.componentWillMount) {
214
- inst.componentWillMount();
215
- // When mounting, calls to `setState` by `componentWillMount` will set
216
- // `this._pendingState` without triggering a re-render.
217
- if (this._pendingState) {
218
- inst.state = this._pendingState;
219
- this._pendingState = null;
199
+ var renderedElement;
200
+
201
+ var previouslyMounting = ReactLifeCycle.currentlyMountingInstance;
202
+ ReactLifeCycle.currentlyMountingInstance = this;
203
+ try {
204
+ if (inst.componentWillMount) {
205
+ inst.componentWillMount();
206
+ // When mounting, calls to `setState` by `componentWillMount` will set
207
+ // `this._pendingStateQueue` without triggering a re-render.
208
+ if (this._pendingStateQueue) {
209
+ inst.state = this._processPendingState(inst.props, inst.context);
210
+ }
220
211
  }
212
+
213
+ renderedElement = this._renderValidatedComponent();
214
+ } finally {
215
+ ReactLifeCycle.currentlyMountingInstance = previouslyMounting;
221
216
  }
222
217
 
223
- var renderedElement = this._renderValidatedComponent();
224
218
  this._renderedComponent = this._instantiateReactComponent(
225
219
  renderedElement,
226
220
  this._currentElement.type // The wrapping type
227
221
  );
228
222
 
229
- // Done with mounting, `setState` will now trigger UI changes.
230
- this._compositeLifeCycleState = null;
231
- var markup = this._renderedComponent.mountComponent(
223
+ var markup = ReactReconciler.mountComponent(
224
+ this._renderedComponent,
232
225
  rootID,
233
226
  transaction,
234
227
  this._processChildContext(context)
@@ -236,6 +229,7 @@ var ReactCompositeComponentMixin = assign({},
236
229
  if (inst.componentDidMount) {
237
230
  transaction.getReactMountReady().enqueue(inst.componentDidMount, inst);
238
231
  }
232
+
239
233
  return markup;
240
234
  },
241
235
 
@@ -248,25 +242,28 @@ var ReactCompositeComponentMixin = assign({},
248
242
  unmountComponent: function() {
249
243
  var inst = this._instance;
250
244
 
251
- this._compositeLifeCycleState = CompositeLifeCycle.UNMOUNTING;
252
245
  if (inst.componentWillUnmount) {
253
- inst.componentWillUnmount();
246
+ var previouslyUnmounting = ReactLifeCycle.currentlyUnmountingInstance;
247
+ ReactLifeCycle.currentlyUnmountingInstance = this;
248
+ try {
249
+ inst.componentWillUnmount();
250
+ } finally {
251
+ ReactLifeCycle.currentlyUnmountingInstance = previouslyUnmounting;
252
+ }
254
253
  }
255
- this._compositeLifeCycleState = null;
256
254
 
257
- this._renderedComponent.unmountComponent();
255
+ ReactReconciler.unmountComponent(this._renderedComponent);
258
256
  this._renderedComponent = null;
259
257
 
260
258
  // Reset pending fields
261
- this._pendingState = null;
259
+ this._pendingStateQueue = null;
260
+ this._pendingReplaceState = false;
262
261
  this._pendingForceUpdate = false;
263
262
  this._pendingCallbacks = null;
264
263
  this._pendingElement = null;
265
264
 
266
- ReactComponent.Mixin.unmountComponent.call(this);
267
-
268
- ReactComponentEnvironment.unmountIDFromEnvironment(this._rootNodeID);
269
-
265
+ // These fields do not really need to be reset since this object is no
266
+ // longer accessible.
270
267
  this._context = null;
271
268
  this._rootNodeID = null;
272
269
 
@@ -282,50 +279,6 @@ var ReactCompositeComponentMixin = assign({},
282
279
  // TODO: inst.context = null;
283
280
  },
284
281
 
285
- /**
286
- * Sets a subset of the props.
287
- *
288
- * @param {object} partialProps Subset of the next props.
289
- * @param {?function} callback Called after props are updated.
290
- * @final
291
- * @public
292
- */
293
- setProps: function(partialProps, callback) {
294
- // Merge with the pending element if it exists, otherwise with existing
295
- // element props.
296
- var element = this._pendingElement || this._currentElement;
297
- this.replaceProps(
298
- assign({}, element.props, partialProps),
299
- callback
300
- );
301
- },
302
-
303
- /**
304
- * Replaces all of the props.
305
- *
306
- * @param {object} props New props.
307
- * @param {?function} callback Called after props are updated.
308
- * @final
309
- * @public
310
- */
311
- replaceProps: function(props, callback) {
312
- ("production" !== process.env.NODE_ENV ? invariant(
313
- this._isTopLevel,
314
- 'replaceProps(...): You called `setProps` or `replaceProps` on a ' +
315
- 'component with a parent. This is an anti-pattern since props will ' +
316
- 'get reactively updated when rendered. Instead, change the owner\'s ' +
317
- '`render` method to pass the correct value as props to the component ' +
318
- 'where it is created.'
319
- ) : invariant(this._isTopLevel));
320
- // This is a deoptimized path. We optimize for always having an element.
321
- // This creates an extra internal element.
322
- this._pendingElement = ReactElement.cloneAndReplaceProps(
323
- this._pendingElement || this._currentElement,
324
- props
325
- );
326
- ReactUpdates.enqueueUpdate(this, callback);
327
- },
328
-
329
282
  /**
330
283
  * Schedule a partial update to the props. Only used for internal testing.
331
284
  *
@@ -345,89 +298,22 @@ var ReactCompositeComponentMixin = assign({},
345
298
  ReactUpdates.enqueueUpdate(this, callback);
346
299
  },
347
300
 
348
- /**
349
- * Sets a subset of the state. This only exists because _pendingState is
350
- * internal. This provides a merging strategy that is not available to deep
351
- * properties which is confusing. TODO: Expose pendingState or don't use it
352
- * during the merge.
353
- *
354
- * @param {object} partialState Next partial state to be merged with state.
355
- * @param {?function} callback Called after state is updated.
356
- * @final
357
- * @protected
358
- */
359
- setState: function(partialState, callback) {
360
- // Merge with `_pendingState` if it exists, otherwise with existing state.
361
- this.replaceState(
362
- assign({}, this._pendingState || this._instance.state, partialState),
363
- callback
364
- );
365
- },
366
-
367
- /**
368
- * Replaces all of the state. Always use this or `setState` to mutate state.
369
- * You should treat `this.state` as immutable.
370
- *
371
- * There is no guarantee that `this.state` will be immediately updated, so
372
- * accessing `this.state` after calling this method may return the old value.
373
- *
374
- * @param {object} completeState Next state.
375
- * @param {?function} callback Called after state is updated.
376
- * @final
377
- * @protected
378
- */
379
- replaceState: function(completeState, callback) {
380
- validateLifeCycleOnReplaceState(this);
381
- this._pendingState = completeState;
382
- if (this._compositeLifeCycleState !== CompositeLifeCycle.MOUNTING) {
383
- // If we're in a componentWillMount handler, don't enqueue a rerender
384
- // because ReactUpdates assumes we're in a browser context (which is wrong
385
- // for server rendering) and we're about to do a render anyway.
386
- // TODO: The callback here is ignored when setState is called from
387
- // componentWillMount. Either fix it or disallow doing so completely in
388
- // favor of getInitialState.
389
- ReactUpdates.enqueueUpdate(this, callback);
390
- }
391
- },
392
-
393
- /**
394
- * Forces an update. This should only be invoked when it is known with
395
- * certainty that we are **not** in a DOM transaction.
396
- *
397
- * You may want to call this when you know that some deeper aspect of the
398
- * component's state has changed but `setState` was not called.
399
- *
400
- * This will not invoke `shouldUpdateComponent`, but it will invoke
401
- * `componentWillUpdate` and `componentDidUpdate`.
402
- *
403
- * @param {?function} callback Called after update is complete.isM
404
- * @final
405
- * @protected
406
- */
407
- forceUpdate: function(callback) {
408
- var compositeLifeCycleState = this._compositeLifeCycleState;
409
- ("production" !== process.env.NODE_ENV ? invariant(
410
- compositeLifeCycleState !== CompositeLifeCycle.RECEIVING_STATE &&
411
- compositeLifeCycleState !== CompositeLifeCycle.UNMOUNTING,
412
- 'forceUpdate(...): Cannot force an update while unmounting component ' +
413
- 'or during an existing state transition (such as within `render`).'
414
- ) : invariant(compositeLifeCycleState !== CompositeLifeCycle.RECEIVING_STATE &&
415
- compositeLifeCycleState !== CompositeLifeCycle.UNMOUNTING));
416
- this._pendingForceUpdate = true;
417
- ReactUpdates.enqueueUpdate(this, callback);
418
- },
419
-
420
301
  /**
421
302
  * Filters the context object to only contain keys specified in
422
- * `contextTypes`, and asserts that they are valid.
303
+ * `contextTypes`
423
304
  *
424
305
  * @param {object} context
425
306
  * @return {?object}
426
307
  * @private
427
308
  */
428
- _processContext: function(context) {
309
+ _maskContext: function(context) {
429
310
  var maskedContext = null;
430
- var contextTypes = this._instance.constructor.contextTypes;
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;
431
317
  if (!contextTypes) {
432
318
  return emptyObject;
433
319
  }
@@ -435,12 +321,30 @@ var ReactCompositeComponentMixin = assign({},
435
321
  for (var contextName in contextTypes) {
436
322
  maskedContext[contextName] = context[contextName];
437
323
  }
324
+ return maskedContext;
325
+ },
326
+
327
+ /**
328
+ * Filters the context object to only contain keys specified in
329
+ * `contextTypes`, and asserts that they are valid.
330
+ *
331
+ * @param {object} context
332
+ * @return {?object}
333
+ * @private
334
+ */
335
+ _processContext: function(context) {
336
+ var maskedContext = this._maskContext(context);
438
337
  if ("production" !== process.env.NODE_ENV) {
439
- this._checkPropTypes(
440
- contextTypes,
441
- maskedContext,
442
- ReactPropTypeLocations.context
338
+ var Component = ReactNativeComponent.getComponentClassForElement(
339
+ this._currentElement
443
340
  );
341
+ if (Component.contextTypes) {
342
+ this._checkPropTypes(
343
+ Component.contextTypes,
344
+ maskedContext,
345
+ ReactPropTypeLocations.context
346
+ );
347
+ }
444
348
  }
445
349
  return maskedContext;
446
350
  },
@@ -453,13 +357,12 @@ var ReactCompositeComponentMixin = assign({},
453
357
  _processChildContext: function(currentContext) {
454
358
  var inst = this._instance;
455
359
  var childContext = inst.getChildContext && inst.getChildContext();
456
- var displayName = inst.constructor.displayName || 'ReactCompositeComponent';
457
360
  if (childContext) {
458
361
  ("production" !== process.env.NODE_ENV ? invariant(
459
362
  typeof inst.constructor.childContextTypes === 'object',
460
363
  '%s.getChildContext(): childContextTypes must be defined in order to ' +
461
364
  'use getChildContext().',
462
- displayName
365
+ this.getName() || 'ReactCompositeComponent'
463
366
  ) : invariant(typeof inst.constructor.childContextTypes === 'object'));
464
367
  if ("production" !== process.env.NODE_ENV) {
465
368
  this._checkPropTypes(
@@ -472,7 +375,7 @@ var ReactCompositeComponentMixin = assign({},
472
375
  ("production" !== process.env.NODE_ENV ? invariant(
473
376
  name in inst.constructor.childContextTypes,
474
377
  '%s.getChildContext(): key "%s" is not defined in childContextTypes.',
475
- displayName,
378
+ this.getName() || 'ReactCompositeComponent',
476
379
  name
477
380
  ) : invariant(name in inst.constructor.childContextTypes));
478
381
  }
@@ -492,10 +395,15 @@ var ReactCompositeComponentMixin = assign({},
492
395
  */
493
396
  _processProps: function(newProps) {
494
397
  if ("production" !== process.env.NODE_ENV) {
495
- var inst = this._instance;
496
- var propTypes = inst.constructor.propTypes;
497
- if (propTypes) {
498
- 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
+ );
499
407
  }
500
408
  }
501
409
  return newProps;
@@ -512,85 +420,97 @@ var ReactCompositeComponentMixin = assign({},
512
420
  _checkPropTypes: function(propTypes, props, location) {
513
421
  // TODO: Stop validating prop types here and only use the element
514
422
  // validation.
515
- var componentName = this._instance.constructor.displayName ||
516
- this._instance.constructor.name;
423
+ var componentName = this.getName();
517
424
  for (var propName in propTypes) {
518
425
  if (propTypes.hasOwnProperty(propName)) {
519
- var error =
520
- 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
+ }
521
442
  if (error instanceof Error) {
522
443
  // We may want to extend this logic for similar errors in
523
444
  // React.render calls, so I'm abstracting it away into
524
445
  // a function to minimize refactoring in the future
525
446
  var addendum = getDeclarationErrorAddendum(this);
526
- ("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
+ }
527
462
  }
528
463
  }
529
464
  }
530
465
  },
531
466
 
532
- receiveComponent: function(nextElement, transaction, context) {
533
- if (nextElement === this._currentElement &&
534
- nextElement._owner != null) {
535
- // Since elements are immutable after the owner is rendered,
536
- // we can do a cheap identity compare here to determine if this is a
537
- // superfluous reconcile. It's possible for state to be mutable but such
538
- // change should trigger an update of the owner which would recreate
539
- // the element. We explicitly check for the existence of an owner since
540
- // it's possible for an element created outside a composite to be
541
- // deeply mutated and reused.
542
- return;
543
- }
467
+ receiveComponent: function(nextElement, transaction, nextContext) {
468
+ var prevElement = this._currentElement;
469
+ var prevContext = this._context;
470
+
471
+ this._pendingElement = null;
544
472
 
545
- this._pendingElement = nextElement;
546
- this._pendingContext = context;
547
- this.performUpdateIfNecessary(transaction);
473
+ this.updateComponent(
474
+ transaction,
475
+ prevElement,
476
+ nextElement,
477
+ prevContext,
478
+ nextContext
479
+ );
548
480
  },
549
481
 
550
482
  /**
551
- * If any of `_pendingElement`, `_pendingState`, or `_pendingForceUpdate`
483
+ * If any of `_pendingElement`, `_pendingStateQueue`, or `_pendingForceUpdate`
552
484
  * is set, update the component.
553
485
  *
554
486
  * @param {ReactReconcileTransaction} transaction
555
487
  * @internal
556
488
  */
557
489
  performUpdateIfNecessary: function(transaction) {
558
- var compositeLifeCycleState = this._compositeLifeCycleState;
559
- // Do not trigger a state transition if we are in the middle of mounting or
560
- // receiving props because both of those will already be doing this.
561
- if (compositeLifeCycleState === CompositeLifeCycle.MOUNTING ||
562
- compositeLifeCycleState === CompositeLifeCycle.RECEIVING_PROPS) {
563
- return;
564
- }
565
-
566
- if (this._pendingElement == null &&
567
- this._pendingState == null &&
568
- this._pendingContext == null &&
569
- !this._pendingForceUpdate) {
570
- return;
571
- }
572
-
573
- var prevElement = this._currentElement;
574
- var nextElement = prevElement;
575
490
  if (this._pendingElement != null) {
576
- nextElement = this._pendingElement;
577
- this._pendingElement = null;
491
+ ReactReconciler.receiveComponent(
492
+ this,
493
+ this._pendingElement || this._currentElement,
494
+ transaction,
495
+ this._context
496
+ );
578
497
  }
579
498
 
580
- var prevContext = this._context;
581
- var nextContext = prevContext;
582
- if (this._pendingContext != null) {
583
- nextContext = this._pendingContext;
584
- this._pendingContext = null;
585
- }
499
+ if (this._pendingStateQueue !== null || this._pendingForceUpdate) {
500
+ if ("production" !== process.env.NODE_ENV) {
501
+ ReactElementValidator.checkAndWarnForMutatedProps(
502
+ this._currentElement
503
+ );
504
+ }
586
505
 
587
- this.updateComponent(
588
- transaction,
589
- prevElement,
590
- nextElement,
591
- prevContext,
592
- nextContext
593
- );
506
+ this.updateComponent(
507
+ transaction,
508
+ this._currentElement,
509
+ this._currentElement,
510
+ this._context,
511
+ this._context
512
+ );
513
+ }
594
514
  },
595
515
 
596
516
  /**
@@ -598,35 +518,22 @@ var ReactCompositeComponentMixin = assign({},
598
518
  * TODO: Remove this check when owner-context is removed
599
519
  */
600
520
  _warnIfContextsDiffer: function(ownerBasedContext, parentBasedContext) {
601
- var ownerKeys = Object.keys(ownerBasedContext).sort();
521
+ ownerBasedContext = this._maskContext(ownerBasedContext);
522
+ parentBasedContext = this._maskContext(parentBasedContext);
602
523
  var parentKeys = Object.keys(parentBasedContext).sort();
603
- var displayName = this._instance.constructor.displayName || 'ReactCompositeComponent';
604
- if (ownerKeys.length !== parentKeys.length ||
605
- ownerKeys.toString() !== parentKeys.toString()) {
524
+ var displayName = this.getName() || 'ReactCompositeComponent';
525
+ for (var i = 0; i < parentKeys.length; i++) {
526
+ var key = parentKeys[i];
606
527
  ("production" !== process.env.NODE_ENV ? warning(
607
- ownerKeys.length === parentKeys.length &&
608
- ownerKeys.toString() === parentKeys.toString(),
609
- 'owner based context (keys: %s) does not equal parent based ' +
610
- 'context (keys: %s) while mounting %s ' +
528
+ ownerBasedContext[key] === parentBasedContext[key],
529
+ 'owner-based and parent-based contexts differ ' +
530
+ '(values: `%s` vs `%s`) for key (%s) while mounting %s ' +
611
531
  '(see: http://fb.me/react-context-by-parent)',
612
- Object.keys(ownerBasedContext),
613
- Object.keys(parentBasedContext),
532
+ ownerBasedContext[key],
533
+ parentBasedContext[key],
534
+ key,
614
535
  displayName
615
536
  ) : null);
616
- } else {
617
- for (var i = 0; i < parentKeys.length; i++) {
618
- var key = parentKeys[i];
619
- ("production" !== process.env.NODE_ENV ? warning(
620
- ownerBasedContext[key] === parentBasedContext[key],
621
- 'owner-based and parent-based contexts differ ' +
622
- '(values: `%s` vs `%s`) for key (%s) while mounting %s ' +
623
- '(see: http://fb.me/react-context-by-parent)',
624
- ownerBasedContext[key],
625
- parentBasedContext[key],
626
- key,
627
- displayName
628
- ) : null);
629
- }
630
537
  }
631
538
  },
632
539
 
@@ -652,37 +559,35 @@ var ReactCompositeComponentMixin = assign({},
652
559
  prevUnmaskedContext,
653
560
  nextUnmaskedContext
654
561
  ) {
655
- // Update refs regardless of what shouldComponentUpdate returns
656
- ReactComponent.Mixin.updateComponent.call(
657
- this,
658
- transaction,
659
- prevParentElement,
660
- nextParentElement,
661
- prevUnmaskedContext,
662
- nextUnmaskedContext
663
- );
664
-
665
562
  var inst = this._instance;
666
563
 
667
- var prevContext = inst.context;
668
- var prevProps = inst.props;
669
- var nextContext = prevContext;
670
- var nextProps = prevProps;
564
+ var nextContext = inst.context;
565
+ var nextProps = inst.props;
566
+
671
567
  // Distinguish between a props update versus a simple state update
672
568
  if (prevParentElement !== nextParentElement) {
673
569
  nextContext = this._processContext(nextParentElement._context);
674
570
  nextProps = this._processProps(nextParentElement.props);
675
571
 
676
- this._compositeLifeCycleState = CompositeLifeCycle.RECEIVING_PROPS;
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
+
677
585
  if (inst.componentWillReceiveProps) {
678
586
  inst.componentWillReceiveProps(nextProps, nextContext);
679
587
  }
680
588
  }
681
589
 
682
- this._compositeLifeCycleState = null;
683
-
684
- var nextState = this._pendingState || inst.state;
685
- this._pendingState = null;
590
+ var nextState = this._processPendingState(nextProps, nextContext);
686
591
 
687
592
  var shouldUpdate =
688
593
  this._pendingForceUpdate ||
@@ -690,16 +595,26 @@ var ReactCompositeComponentMixin = assign({},
690
595
  inst.shouldComponentUpdate(nextProps, nextState, nextContext);
691
596
 
692
597
  if ("production" !== process.env.NODE_ENV) {
693
- if (typeof shouldUpdate === "undefined") {
694
- console.warn(
695
- (inst.constructor.displayName || 'ReactCompositeComponent') +
696
- '.shouldComponentUpdate(): Returned undefined instead of a ' +
697
- 'boolean value. Make sure to return true or false.'
698
- );
699
- }
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);
700
604
  }
701
605
 
702
- if (!shouldUpdate) {
606
+ if (shouldUpdate) {
607
+ this._pendingForceUpdate = false;
608
+ // Will set `this.props`, `this.state` and `this.context`.
609
+ this._performComponentUpdate(
610
+ nextParentElement,
611
+ nextProps,
612
+ nextState,
613
+ nextContext,
614
+ transaction,
615
+ nextUnmaskedContext
616
+ );
617
+ } else {
703
618
  // If it's determined that a component should not update, we still want
704
619
  // to set props and state but we shortcut the rest of the update.
705
620
  this._currentElement = nextParentElement;
@@ -707,19 +622,32 @@ var ReactCompositeComponentMixin = assign({},
707
622
  inst.props = nextProps;
708
623
  inst.state = nextState;
709
624
  inst.context = nextContext;
710
- return;
711
625
  }
626
+ },
712
627
 
713
- this._pendingForceUpdate = false;
714
- // Will set `this.props`, `this.state` and `this.context`.
715
- this._performComponentUpdate(
716
- nextParentElement,
717
- nextProps,
718
- nextState,
719
- nextContext,
720
- transaction,
721
- nextUnmaskedContext
722
- );
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;
723
651
  },
724
652
 
725
653
  /**
@@ -758,7 +686,7 @@ var ReactCompositeComponentMixin = assign({},
758
686
  inst.state = nextState;
759
687
  inst.context = nextContext;
760
688
 
761
- this._updateRenderedComponent(transaction, nextContext);
689
+ this._updateRenderedComponent(transaction, unmaskedContext);
762
690
 
763
691
  if (inst.componentDidUpdate) {
764
692
  transaction.getReactMountReady().enqueue(
@@ -779,7 +707,8 @@ var ReactCompositeComponentMixin = assign({},
779
707
  var prevRenderedElement = prevComponentInstance._currentElement;
780
708
  var nextRenderedElement = this._renderValidatedComponent();
781
709
  if (shouldUpdateReactComponent(prevRenderedElement, nextRenderedElement)) {
782
- prevComponentInstance.receiveComponent(
710
+ ReactReconciler.receiveComponent(
711
+ prevComponentInstance,
783
712
  nextRenderedElement,
784
713
  transaction,
785
714
  this._processChildContext(context)
@@ -788,26 +717,34 @@ var ReactCompositeComponentMixin = assign({},
788
717
  // These two IDs are actually the same! But nothing should rely on that.
789
718
  var thisID = this._rootNodeID;
790
719
  var prevComponentID = prevComponentInstance._rootNodeID;
791
- prevComponentInstance.unmountComponent();
720
+ ReactReconciler.unmountComponent(prevComponentInstance);
792
721
 
793
722
  this._renderedComponent = this._instantiateReactComponent(
794
723
  nextRenderedElement,
795
724
  this._currentElement.type
796
725
  );
797
- var nextMarkup = this._renderedComponent.mountComponent(
726
+ var nextMarkup = ReactReconciler.mountComponent(
727
+ this._renderedComponent,
798
728
  thisID,
799
729
  transaction,
800
730
  context
801
731
  );
802
- ReactComponentEnvironment.replaceNodeWithMarkupByID(
803
- prevComponentID,
804
- nextMarkup
805
- );
732
+ this._replaceNodeWithMarkupByID(prevComponentID, nextMarkup);
806
733
  }
807
734
  },
808
735
 
809
736
  /**
810
- * @private
737
+ * @protected
738
+ */
739
+ _replaceNodeWithMarkupByID: function(prevComponentID, nextMarkup) {
740
+ ReactComponentEnvironment.replaceNodeWithMarkupByID(
741
+ prevComponentID,
742
+ nextMarkup
743
+ );
744
+ },
745
+
746
+ /**
747
+ * @protected
811
748
  */
812
749
  _renderValidatedComponentWithoutOwnerOrContext: function() {
813
750
  var inst = this._instance;
@@ -835,7 +772,6 @@ var ReactCompositeComponentMixin = assign({},
835
772
  this._currentElement._context
836
773
  );
837
774
  ReactCurrentOwner.current = this;
838
- var inst = this._instance;
839
775
  try {
840
776
  renderedComponent =
841
777
  this._renderValidatedComponentWithoutOwnerOrContext();
@@ -849,7 +785,7 @@ var ReactCompositeComponentMixin = assign({},
849
785
  ReactElement.isValidElement(renderedComponent),
850
786
  '%s.render(): A valid ReactComponent must be returned. You may have ' +
851
787
  'returned undefined, an array or some other invalid object.',
852
- inst.constructor.displayName || 'ReactCompositeComponent'
788
+ this.getName() || 'ReactCompositeComponent'
853
789
  ) : invariant(// TODO: An `isValidNode` function would probably be more appropriate
854
790
  renderedComponent === null || renderedComponent === false ||
855
791
  ReactElement.isValidElement(renderedComponent)));
@@ -882,6 +818,22 @@ var ReactCompositeComponentMixin = assign({},
882
818
  delete refs[ref];
883
819
  },
884
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
834
+ );
835
+ },
836
+
885
837
  /**
886
838
  * Get the publicly accessible representation of this component - i.e. what
887
839
  * is exposed by refs and returned by React.render. Can be null for stateless
@@ -897,103 +849,7 @@ var ReactCompositeComponentMixin = assign({},
897
849
  // Stub
898
850
  _instantiateReactComponent: null
899
851
 
900
- });
901
-
902
- var ShallowMixin = assign({},
903
- ReactCompositeComponentMixin, {
904
-
905
- /**
906
- * Initializes the component, renders markup, and registers event listeners.
907
- *
908
- * @param {string} rootID DOM ID of the root node.
909
- * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
910
- * @return {ReactElement} Shallow rendering of the component.
911
- * @final
912
- * @internal
913
- */
914
- mountComponent: function(rootID, transaction, context) {
915
- ReactComponent.Mixin.mountComponent.call(
916
- this,
917
- rootID,
918
- transaction,
919
- context
920
- );
921
-
922
- var inst = this._instance;
923
-
924
- // Store a reference from the instance back to the internal representation
925
- ReactInstanceMap.set(inst, this);
926
-
927
- this._compositeLifeCycleState = CompositeLifeCycle.MOUNTING;
928
-
929
- // No context for shallow-mounted components.
930
- inst.props = this._processProps(this._currentElement.props);
931
-
932
- var initialState = inst.getInitialState ? inst.getInitialState() : null;
933
- if ("production" !== process.env.NODE_ENV) {
934
- // We allow auto-mocks to proceed as if they're returning null.
935
- if (typeof initialState === 'undefined' &&
936
- inst.getInitialState._isMockFunction) {
937
- // This is probably bad practice. Consider warning here and
938
- // deprecating this convenience.
939
- initialState = null;
940
- }
941
- }
942
- ("production" !== process.env.NODE_ENV ? invariant(
943
- typeof initialState === 'object' && !Array.isArray(initialState),
944
- '%s.getInitialState(): must return an object or null',
945
- inst.constructor.displayName || 'ReactCompositeComponent'
946
- ) : invariant(typeof initialState === 'object' && !Array.isArray(initialState)));
947
- inst.state = initialState;
948
-
949
- this._pendingState = null;
950
- this._pendingForceUpdate = false;
951
-
952
- if (inst.componentWillMount) {
953
- inst.componentWillMount();
954
- // When mounting, calls to `setState` by `componentWillMount` will set
955
- // `this._pendingState` without triggering a re-render.
956
- if (this._pendingState) {
957
- inst.state = this._pendingState;
958
- this._pendingState = null;
959
- }
960
- }
961
-
962
- // No recursive call to instantiateReactComponent for shallow rendering.
963
- this._renderedComponent =
964
- this._renderValidatedComponentWithoutOwnerOrContext();
965
-
966
- // Done with mounting, `setState` will now trigger UI changes.
967
- this._compositeLifeCycleState = null;
968
-
969
- // No call to this._renderedComponent.mountComponent for shallow
970
- // rendering.
971
-
972
- if (inst.componentDidMount) {
973
- transaction.getReactMountReady().enqueue(inst.componentDidMount, inst);
974
- }
975
-
976
- return this._renderedComponent;
977
- },
978
-
979
- /**
980
- * Call the component's `render` method and update the DOM accordingly.
981
- *
982
- * @param {ReactReconcileTransaction} transaction
983
- * @internal
984
- */
985
- _updateRenderedComponent: function(transaction) {
986
- var prevComponentInstance = this._renderedComponent;
987
- var prevRenderedElement = prevComponentInstance._currentElement;
988
- // Use the without-owner-or-context variant of _rVC below:
989
- var nextRenderedElement =
990
- this._renderValidatedComponentWithoutOwnerOrContext();
991
- // This is a noop in shallow render
992
- shouldUpdateReactComponent(prevRenderedElement, nextRenderedElement);
993
- this._renderedComponent = nextRenderedElement;
994
- }
995
-
996
- });
852
+ };
997
853
 
998
854
  ReactPerf.measureMethods(
999
855
  ReactCompositeComponentMixin,
@@ -1007,11 +863,7 @@ ReactPerf.measureMethods(
1007
863
 
1008
864
  var ReactCompositeComponent = {
1009
865
 
1010
- LifeCycle: CompositeLifeCycle,
1011
-
1012
- Mixin: ReactCompositeComponentMixin,
1013
-
1014
- ShallowMixin: ShallowMixin
866
+ Mixin: ReactCompositeComponentMixin
1015
867
 
1016
868
  };
1017
869