react 0.6.2 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -217
- package/ReactJSErrors.js +40 -0
- package/addons.js +4 -0
- package/lib/$.js +46 -0
- package/lib/CSSCore.js +114 -0
- package/lib/CSSProperty.js +90 -0
- package/lib/CSSPropertyOperations.js +97 -0
- package/lib/CallbackRegistry.js +91 -0
- package/lib/ChangeEventPlugin.js +365 -0
- package/lib/CompositionEventPlugin.js +212 -0
- package/lib/DOMChildrenOperations.js +135 -0
- package/lib/DOMProperty.js +266 -0
- package/lib/DOMPropertyOperations.js +168 -0
- package/lib/Danger.js +186 -0
- package/lib/DefaultDOMPropertyConfig.js +187 -0
- package/lib/DefaultEventPluginOrder.js +44 -0
- package/lib/EnterLeaveEventPlugin.js +112 -0
- package/lib/EventConstants.js +73 -0
- package/lib/EventListener.js +61 -0
- package/lib/EventPluginHub.js +190 -0
- package/lib/EventPluginRegistry.js +237 -0
- package/lib/EventPluginUtils.js +185 -0
- package/lib/EventPropagators.js +179 -0
- package/lib/ExecutionEnvironment.js +41 -0
- package/lib/LinkedStateMixin.js +46 -0
- package/lib/LinkedValueMixin.js +68 -0
- package/lib/MobileSafariClickEventPlugin.js +63 -0
- package/lib/PooledClass.js +113 -0
- package/lib/React.js +71 -0
- package/lib/ReactChildren.js +132 -0
- package/lib/ReactComponent.js +515 -0
- package/lib/ReactComponentBrowserEnvironment.js +140 -0
- package/lib/ReactComponentEnvironment.js +24 -0
- package/lib/ReactCompositeComponent.js +1020 -0
- package/lib/ReactCurrentOwner.js +39 -0
- package/lib/ReactDOM.js +194 -0
- package/lib/ReactDOMButton.js +64 -0
- package/lib/ReactDOMComponent.js +374 -0
- package/lib/ReactDOMForm.js +52 -0
- package/lib/ReactDOMIDOperations.js +173 -0
- package/lib/ReactDOMInput.js +169 -0
- package/lib/ReactDOMOption.js +50 -0
- package/lib/ReactDOMSelect.js +160 -0
- package/lib/ReactDOMSelection.js +189 -0
- package/lib/ReactDOMTextarea.js +136 -0
- package/lib/ReactDefaultBatchingStrategy.js +75 -0
- package/lib/ReactDefaultInjection.js +91 -0
- package/lib/ReactDefaultPerf.js +407 -0
- package/lib/ReactErrorUtils.js +46 -0
- package/lib/ReactEventEmitter.js +341 -0
- package/lib/ReactEventEmitterMixin.js +89 -0
- package/lib/ReactEventTopLevelCallback.js +89 -0
- package/lib/ReactInputSelection.js +140 -0
- package/lib/ReactInstanceHandles.js +322 -0
- package/lib/ReactLink.js +54 -0
- package/lib/ReactMarkupChecksum.js +53 -0
- package/lib/ReactMount.js +617 -0
- package/lib/ReactMountReady.js +95 -0
- package/lib/ReactMultiChild.js +441 -0
- package/lib/ReactMultiChildUpdateTypes.js +36 -0
- package/lib/ReactOwner.js +146 -0
- package/lib/ReactPerf.js +88 -0
- package/lib/ReactPropTransferer.js +128 -0
- package/lib/ReactPropTypes.js +158 -0
- package/lib/ReactReconcileTransaction.js +161 -0
- package/lib/ReactServerRendering.js +62 -0
- package/lib/ReactStateSetters.js +111 -0
- package/lib/ReactTextComponent.js +94 -0
- package/lib/ReactTransitionEvents.js +97 -0
- package/lib/ReactTransitionGroup.js +112 -0
- package/lib/ReactTransitionKeySet.js +111 -0
- package/lib/ReactTransitionableChild.js +152 -0
- package/lib/ReactUpdates.js +145 -0
- package/lib/ReactWithAddons.js +41 -0
- package/lib/SelectEventPlugin.js +217 -0
- package/lib/SimpleEventPlugin.js +365 -0
- package/lib/SyntheticClipboardEvent.js +45 -0
- package/lib/SyntheticCompositionEvent.js +51 -0
- package/lib/SyntheticEvent.js +163 -0
- package/lib/SyntheticFocusEvent.js +44 -0
- package/lib/SyntheticKeyboardEvent.js +56 -0
- package/lib/SyntheticMouseEvent.js +85 -0
- package/lib/SyntheticTouchEvent.js +50 -0
- package/lib/SyntheticUIEvent.js +45 -0
- package/lib/SyntheticWheelEvent.js +63 -0
- package/lib/Transaction.js +251 -0
- package/lib/ViewportMetrics.js +37 -0
- package/lib/accumulate.js +54 -0
- package/lib/adler32.js +39 -0
- package/lib/containsNode.js +49 -0
- package/lib/copyProperties.js +54 -0
- package/lib/createArrayFrom.js +94 -0
- package/lib/createNodesFromMarkup.js +93 -0
- package/lib/createObjectFrom.js +61 -0
- package/lib/cx.js +44 -0
- package/lib/dangerousStyleValue.js +57 -0
- package/lib/emptyFunction.js +43 -0
- package/lib/escapeTextForBrowser.js +47 -0
- package/lib/ex.js +49 -0
- package/lib/filterAttributes.js +45 -0
- package/lib/flattenChildren.js +54 -0
- package/lib/forEachAccumulated.js +36 -0
- package/lib/ge.js +76 -0
- package/lib/getActiveElement.js +33 -0
- package/lib/getEventTarget.js +36 -0
- package/lib/getMarkupWrap.js +108 -0
- package/lib/getNodeForCharacterOffset.js +80 -0
- package/lib/getReactRootElementInContainer.js +40 -0
- package/lib/getTextContentAccessor.js +40 -0
- package/lib/getUnboundedScrollPosition.js +45 -0
- package/lib/hyphenate.js +35 -0
- package/lib/invariant.js +54 -0
- package/lib/isEventSupported.js +74 -0
- package/lib/isNode.js +33 -0
- package/lib/isTextInputElement.js +49 -0
- package/lib/isTextNode.js +30 -0
- package/lib/joinClasses.js +44 -0
- package/lib/keyMirror.js +58 -0
- package/lib/keyOf.js +41 -0
- package/lib/memoizeStringOnly.js +39 -0
- package/lib/merge.js +37 -0
- package/lib/mergeHelpers.js +137 -0
- package/lib/mergeInto.js +45 -0
- package/lib/mixInto.js +34 -0
- package/lib/mutateHTMLNodeWithMarkup.js +100 -0
- package/lib/objMap.js +47 -0
- package/lib/objMapKeyVal.js +47 -0
- package/lib/performanceNow.js +42 -0
- package/lib/shallowEqual.js +49 -0
- package/lib/traverseAllChildren.js +127 -0
- package/package.json +33 -21
- package/react.js +4 -0
- package/.npmignore +0 -7
- package/.travis.yml +0 -5
- package/Jakefile.js +0 -39
- package/LICENSE +0 -19
- package/browser-test/dist.html +0 -89
- package/browser-test/index.html +0 -85
- package/browser-test/min.html +0 -89
- package/dist/react.js +0 -3094
- package/dist/react.min.js +0 -22
- package/doc/advanced.md +0 -166
- package/doc/color-def.graffle +0 -938
- package/doc/color-def.png +0 -0
- package/doc/simple.dot +0 -25
- package/doc/simple.png +0 -0
- package/examples/longer-example.js +0 -41
- package/examples/simple.js +0 -45
- package/examples/using-ast-directly.js +0 -30
- package/examples/using-events1.js +0 -79
- package/examples/using-log-events.js +0 -43
- package/lib/base-task.js +0 -123
- package/lib/cb-task.js +0 -84
- package/lib/core.js +0 -138
- package/lib/dsl.js +0 -138
- package/lib/error.js +0 -55
- package/lib/event-collector.js +0 -81
- package/lib/event-manager.js +0 -85
- package/lib/eventemitter.js +0 -20
- package/lib/finalcb-first-task.js +0 -68
- package/lib/finalcb-task.js +0 -65
- package/lib/id.js +0 -22
- package/lib/input-parser.js +0 -56
- package/lib/log-events.js +0 -92
- package/lib/parse.js +0 -41
- package/lib/promise-resolve.js +0 -50
- package/lib/promise-task.js +0 -93
- package/lib/react.js +0 -59
- package/lib/ret-task.js +0 -71
- package/lib/sprintf.js +0 -18
- package/lib/status.js +0 -14
- package/lib/task.js +0 -251
- package/lib/track-tasks.js +0 -74
- package/lib/validate.js +0 -159
- package/lib/vcon.js +0 -90
- package/lib/when-task.js +0 -85
- package/src/dist.build.requirejs +0 -20
- package/test/ast.mocha.js +0 -136
- package/test/cb-task.mocha.js +0 -220
- package/test/core-deferred.mocha.js +0 -143
- package/test/core-when.mocha.js +0 -96
- package/test/core.mocha.js +0 -589
- package/test/dsl.mocha.js +0 -350
- package/test/event-manager.mocha.js +0 -119
- package/test/exec-options.mocha.js +0 -48
- package/test/finalcb-task.mocha.js +0 -58
- package/test/input-parser.mocha.js +0 -86
- package/test/mocha.opts +0 -2
- package/test/module-use.mocha.js +0 -147
- package/test/promise-auto-resolve.mocha.js +0 -68
- package/test/ret-task.mocha.js +0 -220
- package/test/task.mocha.js +0 -42
- package/test/validate-cb-task.mocha.js +0 -100
- package/test/validate-ret-task.mocha.js +0 -110
- package/test/validate.mocha.js +0 -324
- package/test/vcon.mocha.js +0 -193
- package/vendor/chai/chai.js +0 -2038
- package/vendor/jquery/jquery-1.7.1.js +0 -9266
- package/vendor/jquery/jquery-1.7.1.min.js +0 -4
- package/vendor/mocha/mocha.css +0 -135
- package/vendor/mocha/mocha.js +0 -3589
- package/vendor/node/util.js +0 -531
- package/vendor/requirejs/require.js +0 -2053
- package/vendor/requirejs/require.min.js +0 -33
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2013 Facebook, Inc.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*
|
|
16
|
+
* @providesModule ReactComponentBrowserEnvironment
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/*jslint evil: true */
|
|
20
|
+
|
|
21
|
+
"use strict";
|
|
22
|
+
|
|
23
|
+
var ReactDOMIDOperations = require("./ReactDOMIDOperations");
|
|
24
|
+
var ReactMarkupChecksum = require("./ReactMarkupChecksum");
|
|
25
|
+
var ReactMount = require("./ReactMount");
|
|
26
|
+
var ReactReconcileTransaction = require("./ReactReconcileTransaction");
|
|
27
|
+
|
|
28
|
+
var getReactRootElementInContainer = require("./getReactRootElementInContainer");
|
|
29
|
+
var invariant = require("./invariant");
|
|
30
|
+
var mutateHTMLNodeWithMarkup = require("./mutateHTMLNodeWithMarkup");
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
var ELEMENT_NODE_TYPE = 1;
|
|
34
|
+
var DOC_NODE_TYPE = 9;
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Abstracts away all functionality of `ReactComponent` requires knowledge of
|
|
39
|
+
* the browser context.
|
|
40
|
+
*/
|
|
41
|
+
var ReactComponentBrowserEnvironment = {
|
|
42
|
+
/**
|
|
43
|
+
* Mixed into every component instance.
|
|
44
|
+
*/
|
|
45
|
+
Mixin: {
|
|
46
|
+
/**
|
|
47
|
+
* Returns the DOM node rendered by this component.
|
|
48
|
+
*
|
|
49
|
+
* @return {DOMElement} The root node of this component.
|
|
50
|
+
* @final
|
|
51
|
+
* @protected
|
|
52
|
+
*/
|
|
53
|
+
getDOMNode: function() {
|
|
54
|
+
("production" !== process.env.NODE_ENV ? invariant(
|
|
55
|
+
this.isMounted(),
|
|
56
|
+
'getDOMNode(): A component must be mounted to have a DOM node.'
|
|
57
|
+
) : invariant(this.isMounted()));
|
|
58
|
+
return ReactMount.getNode(this._rootNodeID);
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
|
|
62
|
+
ReactReconcileTransaction: ReactReconcileTransaction,
|
|
63
|
+
|
|
64
|
+
DOMIDOperations: ReactDOMIDOperations,
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* If a particular environment requires that some resources be cleaned up,
|
|
68
|
+
* specify this in the injected Mixin. In the DOM, we would likely want to
|
|
69
|
+
* purge any cached node ID lookups.
|
|
70
|
+
*
|
|
71
|
+
* @private
|
|
72
|
+
*/
|
|
73
|
+
unmountIDFromEnvironment: function(rootNodeID) {
|
|
74
|
+
ReactMount.purgeID(rootNodeID);
|
|
75
|
+
},
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* @param {string} markup Markup string to place into the DOM Element.
|
|
79
|
+
* @param {DOMElement} container DOM Element to insert markup into.
|
|
80
|
+
* @param {boolean} shouldReuseMarkup Should reuse the existing markup in the
|
|
81
|
+
* container if possible.
|
|
82
|
+
*/
|
|
83
|
+
mountImageIntoNode: function(markup, container, shouldReuseMarkup) {
|
|
84
|
+
("production" !== process.env.NODE_ENV ? invariant(
|
|
85
|
+
container && (
|
|
86
|
+
container.nodeType === ELEMENT_NODE_TYPE ||
|
|
87
|
+
container.nodeType === DOC_NODE_TYPE && ReactMount.allowFullPageRender
|
|
88
|
+
),
|
|
89
|
+
'mountComponentIntoNode(...): Target container is not valid.'
|
|
90
|
+
) : invariant(container && (
|
|
91
|
+
container.nodeType === ELEMENT_NODE_TYPE ||
|
|
92
|
+
container.nodeType === DOC_NODE_TYPE && ReactMount.allowFullPageRender
|
|
93
|
+
)));
|
|
94
|
+
if (shouldReuseMarkup) {
|
|
95
|
+
if (ReactMarkupChecksum.canReuseMarkup(
|
|
96
|
+
markup,
|
|
97
|
+
getReactRootElementInContainer(container))) {
|
|
98
|
+
return;
|
|
99
|
+
} else {
|
|
100
|
+
if ("production" !== process.env.NODE_ENV) {
|
|
101
|
+
console.warn(
|
|
102
|
+
'React attempted to use reuse markup in a container but the ' +
|
|
103
|
+
'checksum was invalid. This generally means that you are using ' +
|
|
104
|
+
'server rendering and the markup generated on the server was ' +
|
|
105
|
+
'not what the client was expecting. React injected new markup ' +
|
|
106
|
+
'to compensate which works but you have lost many of the ' +
|
|
107
|
+
'benefits of server rendering. Instead, figure out why the ' +
|
|
108
|
+
'markup being generated is different on the client or server.'
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// You can't naively set the innerHTML of the entire document. You need
|
|
115
|
+
// to mutate documentElement which requires doing some crazy tricks. See
|
|
116
|
+
// mutateHTMLNodeWithMarkup()
|
|
117
|
+
if (container.nodeType === DOC_NODE_TYPE) {
|
|
118
|
+
mutateHTMLNodeWithMarkup(container.documentElement, markup);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Asynchronously inject markup by ensuring that the container is not in
|
|
123
|
+
// the document when settings its `innerHTML`.
|
|
124
|
+
var parent = container.parentNode;
|
|
125
|
+
if (parent) {
|
|
126
|
+
var next = container.nextSibling;
|
|
127
|
+
parent.removeChild(container);
|
|
128
|
+
container.innerHTML = markup;
|
|
129
|
+
if (next) {
|
|
130
|
+
parent.insertBefore(container, next);
|
|
131
|
+
} else {
|
|
132
|
+
parent.appendChild(container);
|
|
133
|
+
}
|
|
134
|
+
} else {
|
|
135
|
+
container.innerHTML = markup;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
module.exports = ReactComponentBrowserEnvironment;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2013 Facebook, Inc.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*
|
|
16
|
+
* @providesModule ReactComponentEnvironment
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
var ReactComponentBrowserEnvironment =
|
|
20
|
+
require("./ReactComponentBrowserEnvironment");
|
|
21
|
+
|
|
22
|
+
var ReactComponentEnvironment = ReactComponentBrowserEnvironment;
|
|
23
|
+
|
|
24
|
+
module.exports = ReactComponentEnvironment;
|
|
@@ -0,0 +1,1020 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2013 Facebook, Inc.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*
|
|
16
|
+
* @providesModule ReactCompositeComponent
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
"use strict";
|
|
20
|
+
|
|
21
|
+
var ReactComponent = require("./ReactComponent");
|
|
22
|
+
var ReactCurrentOwner = require("./ReactCurrentOwner");
|
|
23
|
+
var ReactErrorUtils = require("./ReactErrorUtils");
|
|
24
|
+
var ReactOwner = require("./ReactOwner");
|
|
25
|
+
var ReactPerf = require("./ReactPerf");
|
|
26
|
+
var ReactPropTransferer = require("./ReactPropTransferer");
|
|
27
|
+
var ReactUpdates = require("./ReactUpdates");
|
|
28
|
+
|
|
29
|
+
var invariant = require("./invariant");
|
|
30
|
+
var keyMirror = require("./keyMirror");
|
|
31
|
+
var merge = require("./merge");
|
|
32
|
+
var mixInto = require("./mixInto");
|
|
33
|
+
var objMap = require("./objMap");
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Policies that describe methods in `ReactCompositeComponentInterface`.
|
|
37
|
+
*/
|
|
38
|
+
var SpecPolicy = keyMirror({
|
|
39
|
+
/**
|
|
40
|
+
* These methods may be defined only once by the class specification or mixin.
|
|
41
|
+
*/
|
|
42
|
+
DEFINE_ONCE: null,
|
|
43
|
+
/**
|
|
44
|
+
* These methods may be defined by both the class specification and mixins.
|
|
45
|
+
* Subsequent definitions will be chained. These methods must return void.
|
|
46
|
+
*/
|
|
47
|
+
DEFINE_MANY: null,
|
|
48
|
+
/**
|
|
49
|
+
* These methods are overriding the base ReactCompositeComponent class.
|
|
50
|
+
*/
|
|
51
|
+
OVERRIDE_BASE: null,
|
|
52
|
+
/**
|
|
53
|
+
* These methods are similar to DEFINE_MANY, except we assume they return
|
|
54
|
+
* objects. We try to merge the keys of the return values of all the mixed in
|
|
55
|
+
* functions. If there is a key conflict we throw.
|
|
56
|
+
*/
|
|
57
|
+
DEFINE_MANY_MERGED: null
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Composite components are higher-level components that compose other composite
|
|
62
|
+
* or native components.
|
|
63
|
+
*
|
|
64
|
+
* To create a new type of `ReactCompositeComponent`, pass a specification of
|
|
65
|
+
* your new class to `React.createClass`. The only requirement of your class
|
|
66
|
+
* specification is that you implement a `render` method.
|
|
67
|
+
*
|
|
68
|
+
* var MyComponent = React.createClass({
|
|
69
|
+
* render: function() {
|
|
70
|
+
* return <div>Hello World</div>;
|
|
71
|
+
* }
|
|
72
|
+
* });
|
|
73
|
+
*
|
|
74
|
+
* The class specification supports a specific protocol of methods that have
|
|
75
|
+
* special meaning (e.g. `render`). See `ReactCompositeComponentInterface` for
|
|
76
|
+
* more the comprehensive protocol. Any other properties and methods in the
|
|
77
|
+
* class specification will available on the prototype.
|
|
78
|
+
*
|
|
79
|
+
* @interface ReactCompositeComponentInterface
|
|
80
|
+
* @internal
|
|
81
|
+
*/
|
|
82
|
+
var ReactCompositeComponentInterface = {
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* An array of Mixin objects to include when defining your component.
|
|
86
|
+
*
|
|
87
|
+
* @type {array}
|
|
88
|
+
* @optional
|
|
89
|
+
*/
|
|
90
|
+
mixins: SpecPolicy.DEFINE_MANY,
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Definition of prop types for this component.
|
|
94
|
+
*
|
|
95
|
+
* @type {object}
|
|
96
|
+
* @optional
|
|
97
|
+
*/
|
|
98
|
+
propTypes: SpecPolicy.DEFINE_ONCE,
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
// ==== Definition methods ====
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Invoked when the component is mounted. Values in the mapping will be set on
|
|
106
|
+
* `this.props` if that prop is not specified (i.e. using an `in` check).
|
|
107
|
+
*
|
|
108
|
+
* This method is invoked before `getInitialState` and therefore cannot rely
|
|
109
|
+
* on `this.state` or use `this.setState`.
|
|
110
|
+
*
|
|
111
|
+
* @return {object}
|
|
112
|
+
* @optional
|
|
113
|
+
*/
|
|
114
|
+
getDefaultProps: SpecPolicy.DEFINE_MANY_MERGED,
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Invoked once before the component is mounted. The return value will be used
|
|
118
|
+
* as the initial value of `this.state`.
|
|
119
|
+
*
|
|
120
|
+
* getInitialState: function() {
|
|
121
|
+
* return {
|
|
122
|
+
* isOn: false,
|
|
123
|
+
* fooBaz: new BazFoo()
|
|
124
|
+
* }
|
|
125
|
+
* }
|
|
126
|
+
*
|
|
127
|
+
* @return {object}
|
|
128
|
+
* @optional
|
|
129
|
+
*/
|
|
130
|
+
getInitialState: SpecPolicy.DEFINE_MANY_MERGED,
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Uses props from `this.props` and state from `this.state` to render the
|
|
134
|
+
* structure of the component.
|
|
135
|
+
*
|
|
136
|
+
* No guarantees are made about when or how often this method is invoked, so
|
|
137
|
+
* it must not have side effects.
|
|
138
|
+
*
|
|
139
|
+
* render: function() {
|
|
140
|
+
* var name = this.props.name;
|
|
141
|
+
* return <div>Hello, {name}!</div>;
|
|
142
|
+
* }
|
|
143
|
+
*
|
|
144
|
+
* @return {ReactComponent}
|
|
145
|
+
* @nosideeffects
|
|
146
|
+
* @required
|
|
147
|
+
*/
|
|
148
|
+
render: SpecPolicy.DEFINE_ONCE,
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
// ==== Delegate methods ====
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Invoked when the component is initially created and about to be mounted.
|
|
156
|
+
* This may have side effects, but any external subscriptions or data created
|
|
157
|
+
* by this method must be cleaned up in `componentWillUnmount`.
|
|
158
|
+
*
|
|
159
|
+
* @optional
|
|
160
|
+
*/
|
|
161
|
+
componentWillMount: SpecPolicy.DEFINE_MANY,
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Invoked when the component has been mounted and has a DOM representation.
|
|
165
|
+
* However, there is no guarantee that the DOM node is in the document.
|
|
166
|
+
*
|
|
167
|
+
* Use this as an opportunity to operate on the DOM when the component has
|
|
168
|
+
* been mounted (initialized and rendered) for the first time.
|
|
169
|
+
*
|
|
170
|
+
* @param {DOMElement} rootNode DOM element representing the component.
|
|
171
|
+
* @optional
|
|
172
|
+
*/
|
|
173
|
+
componentDidMount: SpecPolicy.DEFINE_MANY,
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Invoked before the component receives new props.
|
|
177
|
+
*
|
|
178
|
+
* Use this as an opportunity to react to a prop transition by updating the
|
|
179
|
+
* state using `this.setState`. Current props are accessed via `this.props`.
|
|
180
|
+
*
|
|
181
|
+
* componentWillReceiveProps: function(nextProps) {
|
|
182
|
+
* this.setState({
|
|
183
|
+
* likesIncreasing: nextProps.likeCount > this.props.likeCount
|
|
184
|
+
* });
|
|
185
|
+
* }
|
|
186
|
+
*
|
|
187
|
+
* NOTE: There is no equivalent `componentWillReceiveState`. An incoming prop
|
|
188
|
+
* transition may cause a state change, but the opposite is not true. If you
|
|
189
|
+
* need it, you are probably looking for `componentWillUpdate`.
|
|
190
|
+
*
|
|
191
|
+
* @param {object} nextProps
|
|
192
|
+
* @optional
|
|
193
|
+
*/
|
|
194
|
+
componentWillReceiveProps: SpecPolicy.DEFINE_MANY,
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Invoked while deciding if the component should be updated as a result of
|
|
198
|
+
* receiving new props and state.
|
|
199
|
+
*
|
|
200
|
+
* Use this as an opportunity to `return false` when you're certain that the
|
|
201
|
+
* transition to the new props and state will not require a component update.
|
|
202
|
+
*
|
|
203
|
+
* shouldComponentUpdate: function(nextProps, nextState) {
|
|
204
|
+
* return !equal(nextProps, this.props) || !equal(nextState, this.state);
|
|
205
|
+
* }
|
|
206
|
+
*
|
|
207
|
+
* @param {object} nextProps
|
|
208
|
+
* @param {?object} nextState
|
|
209
|
+
* @return {boolean} True if the component should update.
|
|
210
|
+
* @optional
|
|
211
|
+
*/
|
|
212
|
+
shouldComponentUpdate: SpecPolicy.DEFINE_ONCE,
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Invoked when the component is about to update due to a transition from
|
|
216
|
+
* `this.props` and `this.state` to `nextProps` and `nextState`.
|
|
217
|
+
*
|
|
218
|
+
* Use this as an opportunity to perform preparation before an update occurs.
|
|
219
|
+
*
|
|
220
|
+
* NOTE: You **cannot** use `this.setState()` in this method.
|
|
221
|
+
*
|
|
222
|
+
* @param {object} nextProps
|
|
223
|
+
* @param {?object} nextState
|
|
224
|
+
* @param {ReactReconcileTransaction} transaction
|
|
225
|
+
* @optional
|
|
226
|
+
*/
|
|
227
|
+
componentWillUpdate: SpecPolicy.DEFINE_MANY,
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Invoked when the component's DOM representation has been updated.
|
|
231
|
+
*
|
|
232
|
+
* Use this as an opportunity to operate on the DOM when the component has
|
|
233
|
+
* been updated.
|
|
234
|
+
*
|
|
235
|
+
* @param {object} prevProps
|
|
236
|
+
* @param {?object} prevState
|
|
237
|
+
* @param {DOMElement} rootNode DOM element representing the component.
|
|
238
|
+
* @optional
|
|
239
|
+
*/
|
|
240
|
+
componentDidUpdate: SpecPolicy.DEFINE_MANY,
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Invoked when the component is about to be removed from its parent and have
|
|
244
|
+
* its DOM representation destroyed.
|
|
245
|
+
*
|
|
246
|
+
* Use this as an opportunity to deallocate any external resources.
|
|
247
|
+
*
|
|
248
|
+
* NOTE: There is no `componentDidUnmount` since your component will have been
|
|
249
|
+
* destroyed by that point.
|
|
250
|
+
*
|
|
251
|
+
* @optional
|
|
252
|
+
*/
|
|
253
|
+
componentWillUnmount: SpecPolicy.DEFINE_MANY,
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
// ==== Advanced methods ====
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Updates the component's currently mounted DOM representation.
|
|
261
|
+
*
|
|
262
|
+
* By default, this implements React's rendering and reconciliation algorithm.
|
|
263
|
+
* Sophisticated clients may wish to override this.
|
|
264
|
+
*
|
|
265
|
+
* @param {ReactReconcileTransaction} transaction
|
|
266
|
+
* @internal
|
|
267
|
+
* @overridable
|
|
268
|
+
*/
|
|
269
|
+
updateComponent: SpecPolicy.OVERRIDE_BASE
|
|
270
|
+
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Mapping from class specification keys to special processing functions.
|
|
275
|
+
*
|
|
276
|
+
* Although these are declared in the specification when defining classes
|
|
277
|
+
* using `React.createClass`, they will not be on the component's prototype.
|
|
278
|
+
*/
|
|
279
|
+
var RESERVED_SPEC_KEYS = {
|
|
280
|
+
displayName: function(Constructor, displayName) {
|
|
281
|
+
Constructor.displayName = displayName;
|
|
282
|
+
},
|
|
283
|
+
mixins: function(Constructor, mixins) {
|
|
284
|
+
if (mixins) {
|
|
285
|
+
for (var i = 0; i < mixins.length; i++) {
|
|
286
|
+
mixSpecIntoComponent(Constructor, mixins[i]);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
},
|
|
290
|
+
propTypes: function(Constructor, propTypes) {
|
|
291
|
+
Constructor.propTypes = propTypes;
|
|
292
|
+
}
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
function validateMethodOverride(proto, name) {
|
|
296
|
+
var specPolicy = ReactCompositeComponentInterface[name];
|
|
297
|
+
|
|
298
|
+
// Disallow overriding of base class methods unless explicitly allowed.
|
|
299
|
+
if (ReactCompositeComponentMixin.hasOwnProperty(name)) {
|
|
300
|
+
("production" !== process.env.NODE_ENV ? invariant(
|
|
301
|
+
specPolicy === SpecPolicy.OVERRIDE_BASE,
|
|
302
|
+
'ReactCompositeComponentInterface: You are attempting to override ' +
|
|
303
|
+
'`%s` from your class specification. Ensure that your method names ' +
|
|
304
|
+
'do not overlap with React methods.',
|
|
305
|
+
name
|
|
306
|
+
) : invariant(specPolicy === SpecPolicy.OVERRIDE_BASE));
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// Disallow defining methods more than once unless explicitly allowed.
|
|
310
|
+
if (proto.hasOwnProperty(name)) {
|
|
311
|
+
("production" !== process.env.NODE_ENV ? invariant(
|
|
312
|
+
specPolicy === SpecPolicy.DEFINE_MANY ||
|
|
313
|
+
specPolicy === SpecPolicy.DEFINE_MANY_MERGED,
|
|
314
|
+
'ReactCompositeComponentInterface: You are attempting to define ' +
|
|
315
|
+
'`%s` on your component more than once. This conflict may be due ' +
|
|
316
|
+
'to a mixin.',
|
|
317
|
+
name
|
|
318
|
+
) : invariant(specPolicy === SpecPolicy.DEFINE_MANY ||
|
|
319
|
+
specPolicy === SpecPolicy.DEFINE_MANY_MERGED));
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
function validateLifeCycleOnReplaceState(instance) {
|
|
325
|
+
var compositeLifeCycleState = instance._compositeLifeCycleState;
|
|
326
|
+
("production" !== process.env.NODE_ENV ? invariant(
|
|
327
|
+
instance.isMounted() ||
|
|
328
|
+
compositeLifeCycleState === CompositeLifeCycle.MOUNTING,
|
|
329
|
+
'replaceState(...): Can only update a mounted or mounting component.'
|
|
330
|
+
) : invariant(instance.isMounted() ||
|
|
331
|
+
compositeLifeCycleState === CompositeLifeCycle.MOUNTING));
|
|
332
|
+
("production" !== process.env.NODE_ENV ? invariant(compositeLifeCycleState !== CompositeLifeCycle.RECEIVING_STATE,
|
|
333
|
+
'replaceState(...): Cannot update during an existing state transition ' +
|
|
334
|
+
'(such as within `render`). This could potentially cause an infinite ' +
|
|
335
|
+
'loop so it is forbidden.'
|
|
336
|
+
) : invariant(compositeLifeCycleState !== CompositeLifeCycle.RECEIVING_STATE));
|
|
337
|
+
("production" !== process.env.NODE_ENV ? invariant(compositeLifeCycleState !== CompositeLifeCycle.UNMOUNTING,
|
|
338
|
+
'replaceState(...): Cannot update while unmounting component. This ' +
|
|
339
|
+
'usually means you called setState() on an unmounted component.'
|
|
340
|
+
) : invariant(compositeLifeCycleState !== CompositeLifeCycle.UNMOUNTING));
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* Custom version of `mixInto` which handles policy validation and reserved
|
|
345
|
+
* specification keys when building `ReactCompositeComponent` classses.
|
|
346
|
+
*/
|
|
347
|
+
function mixSpecIntoComponent(Constructor, spec) {
|
|
348
|
+
var proto = Constructor.prototype;
|
|
349
|
+
for (var name in spec) {
|
|
350
|
+
var property = spec[name];
|
|
351
|
+
if (!spec.hasOwnProperty(name) || !property) {
|
|
352
|
+
continue;
|
|
353
|
+
}
|
|
354
|
+
validateMethodOverride(proto, name);
|
|
355
|
+
|
|
356
|
+
if (RESERVED_SPEC_KEYS.hasOwnProperty(name)) {
|
|
357
|
+
RESERVED_SPEC_KEYS[name](Constructor, property);
|
|
358
|
+
} else {
|
|
359
|
+
// Setup methods on prototype:
|
|
360
|
+
// The following member methods should not be automatically bound:
|
|
361
|
+
// 1. Expected ReactCompositeComponent methods (in the "interface").
|
|
362
|
+
// 2. Overridden methods (that were mixed in).
|
|
363
|
+
var isCompositeComponentMethod = name in ReactCompositeComponentInterface;
|
|
364
|
+
var isInherited = name in proto;
|
|
365
|
+
var markedDontBind = property.__reactDontBind;
|
|
366
|
+
var isFunction = typeof property === 'function';
|
|
367
|
+
var shouldAutoBind =
|
|
368
|
+
isFunction &&
|
|
369
|
+
!isCompositeComponentMethod &&
|
|
370
|
+
!isInherited &&
|
|
371
|
+
!markedDontBind;
|
|
372
|
+
|
|
373
|
+
if (shouldAutoBind) {
|
|
374
|
+
if (!proto.__reactAutoBindMap) {
|
|
375
|
+
proto.__reactAutoBindMap = {};
|
|
376
|
+
}
|
|
377
|
+
proto.__reactAutoBindMap[name] = property;
|
|
378
|
+
proto[name] = property;
|
|
379
|
+
} else {
|
|
380
|
+
if (isInherited) {
|
|
381
|
+
// For methods which are defined more than once, call the existing
|
|
382
|
+
// methods before calling the new property.
|
|
383
|
+
if (ReactCompositeComponentInterface[name] ===
|
|
384
|
+
SpecPolicy.DEFINE_MANY_MERGED) {
|
|
385
|
+
proto[name] = createMergedResultFunction(proto[name], property);
|
|
386
|
+
} else {
|
|
387
|
+
proto[name] = createChainedFunction(proto[name], property);
|
|
388
|
+
}
|
|
389
|
+
} else {
|
|
390
|
+
proto[name] = property;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
/**
|
|
398
|
+
* Merge two objects, but throw if both contain the same key.
|
|
399
|
+
*
|
|
400
|
+
* @param {object} one The first object, which is mutated.
|
|
401
|
+
* @param {object} two The second object
|
|
402
|
+
* @return {object} one after it has been mutated to contain everything in two.
|
|
403
|
+
*/
|
|
404
|
+
function mergeObjectsWithNoDuplicateKeys(one, two) {
|
|
405
|
+
("production" !== process.env.NODE_ENV ? invariant(
|
|
406
|
+
one && two && typeof one === 'object' && typeof two === 'object',
|
|
407
|
+
'mergeObjectsWithNoDuplicateKeys(): Cannot merge non-objects'
|
|
408
|
+
) : invariant(one && two && typeof one === 'object' && typeof two === 'object'));
|
|
409
|
+
|
|
410
|
+
objMap(two, function(value, key) {
|
|
411
|
+
("production" !== process.env.NODE_ENV ? invariant(
|
|
412
|
+
one[key] === undefined,
|
|
413
|
+
'mergeObjectsWithNoDuplicateKeys(): ' +
|
|
414
|
+
'Tried to merge two objects with the same key: %s',
|
|
415
|
+
key
|
|
416
|
+
) : invariant(one[key] === undefined));
|
|
417
|
+
one[key] = value;
|
|
418
|
+
});
|
|
419
|
+
return one;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* Creates a function that invokes two functions and merges their return values.
|
|
424
|
+
*
|
|
425
|
+
* @param {function} one Function to invoke first.
|
|
426
|
+
* @param {function} two Function to invoke second.
|
|
427
|
+
* @return {function} Function that invokes the two argument functions.
|
|
428
|
+
* @private
|
|
429
|
+
*/
|
|
430
|
+
function createMergedResultFunction(one, two) {
|
|
431
|
+
return function mergedResult() {
|
|
432
|
+
return mergeObjectsWithNoDuplicateKeys(
|
|
433
|
+
one.apply(this, arguments),
|
|
434
|
+
two.apply(this, arguments)
|
|
435
|
+
);
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* Creates a function that invokes two functions and ignores their return vales.
|
|
441
|
+
*
|
|
442
|
+
* @param {function} one Function to invoke first.
|
|
443
|
+
* @param {function} two Function to invoke second.
|
|
444
|
+
* @return {function} Function that invokes the two argument functions.
|
|
445
|
+
* @private
|
|
446
|
+
*/
|
|
447
|
+
function createChainedFunction(one, two) {
|
|
448
|
+
return function chainedFunction() {
|
|
449
|
+
one.apply(this, arguments);
|
|
450
|
+
two.apply(this, arguments);
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
/**
|
|
455
|
+
* `ReactCompositeComponent` maintains an auxiliary life cycle state in
|
|
456
|
+
* `this._compositeLifeCycleState` (which can be null).
|
|
457
|
+
*
|
|
458
|
+
* This is different from the life cycle state maintained by `ReactComponent` in
|
|
459
|
+
* `this._lifeCycleState`. The following diagram shows how the states overlap in
|
|
460
|
+
* time. There are times when the CompositeLifeCycle is null - at those times it
|
|
461
|
+
* is only meaningful to look at ComponentLifeCycle alone.
|
|
462
|
+
*
|
|
463
|
+
* Top Row: ReactComponent.ComponentLifeCycle
|
|
464
|
+
* Low Row: ReactComponent.CompositeLifeCycle
|
|
465
|
+
*
|
|
466
|
+
* +-------+------------------------------------------------------+--------+
|
|
467
|
+
* | UN | MOUNTED | UN |
|
|
468
|
+
* |MOUNTED| | MOUNTED|
|
|
469
|
+
* +-------+------------------------------------------------------+--------+
|
|
470
|
+
* | ^--------+ +------+ +------+ +------+ +--------^ |
|
|
471
|
+
* | | | | | | | | | | | |
|
|
472
|
+
* | 0--|MOUNTING|-0-|RECEIV|-0-|RECEIV|-0-|RECEIV|-0-| UN |--->0 |
|
|
473
|
+
* | | | |PROPS | | PROPS| | STATE| |MOUNTING| |
|
|
474
|
+
* | | | | | | | | | | | |
|
|
475
|
+
* | | | | | | | | | | | |
|
|
476
|
+
* | +--------+ +------+ +------+ +------+ +--------+ |
|
|
477
|
+
* | | | |
|
|
478
|
+
* +-------+------------------------------------------------------+--------+
|
|
479
|
+
*/
|
|
480
|
+
var CompositeLifeCycle = keyMirror({
|
|
481
|
+
/**
|
|
482
|
+
* Components in the process of being mounted respond to state changes
|
|
483
|
+
* differently.
|
|
484
|
+
*/
|
|
485
|
+
MOUNTING: null,
|
|
486
|
+
/**
|
|
487
|
+
* Components in the process of being unmounted are guarded against state
|
|
488
|
+
* changes.
|
|
489
|
+
*/
|
|
490
|
+
UNMOUNTING: null,
|
|
491
|
+
/**
|
|
492
|
+
* Components that are mounted and receiving new props respond to state
|
|
493
|
+
* changes differently.
|
|
494
|
+
*/
|
|
495
|
+
RECEIVING_PROPS: null,
|
|
496
|
+
/**
|
|
497
|
+
* Components that are mounted and receiving new state are guarded against
|
|
498
|
+
* additional state changes.
|
|
499
|
+
*/
|
|
500
|
+
RECEIVING_STATE: null
|
|
501
|
+
});
|
|
502
|
+
|
|
503
|
+
/**
|
|
504
|
+
* @lends {ReactCompositeComponent.prototype}
|
|
505
|
+
*/
|
|
506
|
+
var ReactCompositeComponentMixin = {
|
|
507
|
+
|
|
508
|
+
/**
|
|
509
|
+
* Base constructor for all composite component.
|
|
510
|
+
*
|
|
511
|
+
* @param {?object} initialProps
|
|
512
|
+
* @param {*} children
|
|
513
|
+
* @final
|
|
514
|
+
* @internal
|
|
515
|
+
*/
|
|
516
|
+
construct: function(initialProps, children) {
|
|
517
|
+
// Children can be either an array or more than one argument
|
|
518
|
+
ReactComponent.Mixin.construct.apply(this, arguments);
|
|
519
|
+
this.state = null;
|
|
520
|
+
this._pendingState = null;
|
|
521
|
+
this._compositeLifeCycleState = null;
|
|
522
|
+
},
|
|
523
|
+
|
|
524
|
+
/**
|
|
525
|
+
* Checks whether or not this composite component is mounted.
|
|
526
|
+
* @return {boolean} True if mounted, false otherwise.
|
|
527
|
+
* @protected
|
|
528
|
+
* @final
|
|
529
|
+
*/
|
|
530
|
+
isMounted: function() {
|
|
531
|
+
return ReactComponent.Mixin.isMounted.call(this) &&
|
|
532
|
+
this._compositeLifeCycleState !== CompositeLifeCycle.MOUNTING;
|
|
533
|
+
},
|
|
534
|
+
|
|
535
|
+
/**
|
|
536
|
+
* Initializes the component, renders markup, and registers event listeners.
|
|
537
|
+
*
|
|
538
|
+
* @param {string} rootID DOM ID of the root node.
|
|
539
|
+
* @param {ReactReconcileTransaction} transaction
|
|
540
|
+
* @param {number} mountDepth number of components in the owner hierarchy
|
|
541
|
+
* @return {?string} Rendered markup to be inserted into the DOM.
|
|
542
|
+
* @final
|
|
543
|
+
* @internal
|
|
544
|
+
*/
|
|
545
|
+
mountComponent: ReactPerf.measure(
|
|
546
|
+
'ReactCompositeComponent',
|
|
547
|
+
'mountComponent',
|
|
548
|
+
function(rootID, transaction, mountDepth) {
|
|
549
|
+
ReactComponent.Mixin.mountComponent.call(
|
|
550
|
+
this,
|
|
551
|
+
rootID,
|
|
552
|
+
transaction,
|
|
553
|
+
mountDepth
|
|
554
|
+
);
|
|
555
|
+
this._compositeLifeCycleState = CompositeLifeCycle.MOUNTING;
|
|
556
|
+
|
|
557
|
+
this._defaultProps = this.getDefaultProps ? this.getDefaultProps() : null;
|
|
558
|
+
this._processProps(this.props);
|
|
559
|
+
|
|
560
|
+
if (this.__reactAutoBindMap) {
|
|
561
|
+
this._bindAutoBindMethods();
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
this.state = this.getInitialState ? this.getInitialState() : null;
|
|
565
|
+
this._pendingState = null;
|
|
566
|
+
this._pendingForceUpdate = false;
|
|
567
|
+
|
|
568
|
+
if (this.componentWillMount) {
|
|
569
|
+
this.componentWillMount();
|
|
570
|
+
// When mounting, calls to `setState` by `componentWillMount` will set
|
|
571
|
+
// `this._pendingState` without triggering a re-render.
|
|
572
|
+
if (this._pendingState) {
|
|
573
|
+
this.state = this._pendingState;
|
|
574
|
+
this._pendingState = null;
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
this._renderedComponent = this._renderValidatedComponent();
|
|
579
|
+
|
|
580
|
+
// Done with mounting, `setState` will now trigger UI changes.
|
|
581
|
+
this._compositeLifeCycleState = null;
|
|
582
|
+
var markup = this._renderedComponent.mountComponent(
|
|
583
|
+
rootID,
|
|
584
|
+
transaction,
|
|
585
|
+
mountDepth + 1
|
|
586
|
+
);
|
|
587
|
+
if (this.componentDidMount) {
|
|
588
|
+
transaction.getReactMountReady().enqueue(this, this.componentDidMount);
|
|
589
|
+
}
|
|
590
|
+
return markup;
|
|
591
|
+
}
|
|
592
|
+
),
|
|
593
|
+
|
|
594
|
+
/**
|
|
595
|
+
* Releases any resources allocated by `mountComponent`.
|
|
596
|
+
*
|
|
597
|
+
* @final
|
|
598
|
+
* @internal
|
|
599
|
+
*/
|
|
600
|
+
unmountComponent: function() {
|
|
601
|
+
this._compositeLifeCycleState = CompositeLifeCycle.UNMOUNTING;
|
|
602
|
+
if (this.componentWillUnmount) {
|
|
603
|
+
this.componentWillUnmount();
|
|
604
|
+
}
|
|
605
|
+
this._compositeLifeCycleState = null;
|
|
606
|
+
|
|
607
|
+
this._defaultProps = null;
|
|
608
|
+
|
|
609
|
+
ReactComponent.Mixin.unmountComponent.call(this);
|
|
610
|
+
this._renderedComponent.unmountComponent();
|
|
611
|
+
this._renderedComponent = null;
|
|
612
|
+
|
|
613
|
+
if (this.refs) {
|
|
614
|
+
this.refs = null;
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
// Some existing components rely on this.props even after they've been
|
|
618
|
+
// destroyed (in event handlers).
|
|
619
|
+
// TODO: this.props = null;
|
|
620
|
+
// TODO: this.state = null;
|
|
621
|
+
},
|
|
622
|
+
|
|
623
|
+
/**
|
|
624
|
+
* Sets a subset of the state. Always use this or `replaceState` to mutate
|
|
625
|
+
* state. You should treat `this.state` as immutable.
|
|
626
|
+
*
|
|
627
|
+
* There is no guarantee that `this.state` will be immediately updated, so
|
|
628
|
+
* accessing `this.state` after calling this method may return the old value.
|
|
629
|
+
*
|
|
630
|
+
* There is no guarantee that calls to `setState` will run synchronously,
|
|
631
|
+
* as they may eventually be batched together. You can provide an optional
|
|
632
|
+
* callback that will be executed when the call to setState is actually
|
|
633
|
+
* completed.
|
|
634
|
+
*
|
|
635
|
+
* @param {object} partialState Next partial state to be merged with state.
|
|
636
|
+
* @param {?function} callback Called after state is updated.
|
|
637
|
+
* @final
|
|
638
|
+
* @protected
|
|
639
|
+
*/
|
|
640
|
+
setState: function(partialState, callback) {
|
|
641
|
+
// Merge with `_pendingState` if it exists, otherwise with existing state.
|
|
642
|
+
this.replaceState(
|
|
643
|
+
merge(this._pendingState || this.state, partialState),
|
|
644
|
+
callback
|
|
645
|
+
);
|
|
646
|
+
},
|
|
647
|
+
|
|
648
|
+
/**
|
|
649
|
+
* Replaces all of the state. Always use this or `setState` to mutate state.
|
|
650
|
+
* You should treat `this.state` as immutable.
|
|
651
|
+
*
|
|
652
|
+
* There is no guarantee that `this.state` will be immediately updated, so
|
|
653
|
+
* accessing `this.state` after calling this method may return the old value.
|
|
654
|
+
*
|
|
655
|
+
* @param {object} completeState Next state.
|
|
656
|
+
* @param {?function} callback Called after state is updated.
|
|
657
|
+
* @final
|
|
658
|
+
* @protected
|
|
659
|
+
*/
|
|
660
|
+
replaceState: function(completeState, callback) {
|
|
661
|
+
validateLifeCycleOnReplaceState(this);
|
|
662
|
+
this._pendingState = completeState;
|
|
663
|
+
ReactUpdates.enqueueUpdate(this, callback);
|
|
664
|
+
},
|
|
665
|
+
|
|
666
|
+
/**
|
|
667
|
+
* Processes props by setting default values for unspecified props and
|
|
668
|
+
* asserting that the props are valid.
|
|
669
|
+
*
|
|
670
|
+
* @param {object} props
|
|
671
|
+
* @private
|
|
672
|
+
*/
|
|
673
|
+
_processProps: function(props) {
|
|
674
|
+
var propName;
|
|
675
|
+
var defaultProps = this._defaultProps;
|
|
676
|
+
for (propName in defaultProps) {
|
|
677
|
+
if (!(propName in props)) {
|
|
678
|
+
props[propName] = defaultProps[propName];
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
var propTypes = this.constructor.propTypes;
|
|
682
|
+
if (propTypes) {
|
|
683
|
+
var componentName = this.constructor.displayName;
|
|
684
|
+
for (propName in propTypes) {
|
|
685
|
+
var checkProp = propTypes[propName];
|
|
686
|
+
if (checkProp) {
|
|
687
|
+
checkProp(props, propName, componentName);
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
},
|
|
692
|
+
|
|
693
|
+
performUpdateIfNecessary: function() {
|
|
694
|
+
var compositeLifeCycleState = this._compositeLifeCycleState;
|
|
695
|
+
// Do not trigger a state transition if we are in the middle of mounting or
|
|
696
|
+
// receiving props because both of those will already be doing this.
|
|
697
|
+
if (compositeLifeCycleState === CompositeLifeCycle.MOUNTING ||
|
|
698
|
+
compositeLifeCycleState === CompositeLifeCycle.RECEIVING_PROPS) {
|
|
699
|
+
return;
|
|
700
|
+
}
|
|
701
|
+
ReactComponent.Mixin.performUpdateIfNecessary.call(this);
|
|
702
|
+
},
|
|
703
|
+
|
|
704
|
+
/**
|
|
705
|
+
* If any of `_pendingProps`, `_pendingState`, or `_pendingForceUpdate` is
|
|
706
|
+
* set, update the component.
|
|
707
|
+
*
|
|
708
|
+
* @param {ReactReconcileTransaction} transaction
|
|
709
|
+
* @internal
|
|
710
|
+
*/
|
|
711
|
+
_performUpdateIfNecessary: function(transaction) {
|
|
712
|
+
if (this._pendingProps == null &&
|
|
713
|
+
this._pendingState == null &&
|
|
714
|
+
!this._pendingForceUpdate) {
|
|
715
|
+
return;
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
var nextProps = this.props;
|
|
719
|
+
if (this._pendingProps != null) {
|
|
720
|
+
nextProps = this._pendingProps;
|
|
721
|
+
this._processProps(nextProps);
|
|
722
|
+
this._pendingProps = null;
|
|
723
|
+
|
|
724
|
+
this._compositeLifeCycleState = CompositeLifeCycle.RECEIVING_PROPS;
|
|
725
|
+
if (this.componentWillReceiveProps) {
|
|
726
|
+
this.componentWillReceiveProps(nextProps, transaction);
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
this._compositeLifeCycleState = CompositeLifeCycle.RECEIVING_STATE;
|
|
731
|
+
|
|
732
|
+
var nextState = this._pendingState || this.state;
|
|
733
|
+
this._pendingState = null;
|
|
734
|
+
|
|
735
|
+
if (this._pendingForceUpdate ||
|
|
736
|
+
!this.shouldComponentUpdate ||
|
|
737
|
+
this.shouldComponentUpdate(nextProps, nextState)) {
|
|
738
|
+
this._pendingForceUpdate = false;
|
|
739
|
+
// Will set `this.props` and `this.state`.
|
|
740
|
+
this._performComponentUpdate(nextProps, nextState, transaction);
|
|
741
|
+
} else {
|
|
742
|
+
// If it's determined that a component should not update, we still want
|
|
743
|
+
// to set props and state.
|
|
744
|
+
this.props = nextProps;
|
|
745
|
+
this.state = nextState;
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
this._compositeLifeCycleState = null;
|
|
749
|
+
},
|
|
750
|
+
|
|
751
|
+
/**
|
|
752
|
+
* Merges new props and state, notifies delegate methods of update and
|
|
753
|
+
* performs update.
|
|
754
|
+
*
|
|
755
|
+
* @param {object} nextProps Next object to set as properties.
|
|
756
|
+
* @param {?object} nextState Next object to set as state.
|
|
757
|
+
* @param {ReactReconcileTransaction} transaction
|
|
758
|
+
* @private
|
|
759
|
+
*/
|
|
760
|
+
_performComponentUpdate: function(nextProps, nextState, transaction) {
|
|
761
|
+
var prevProps = this.props;
|
|
762
|
+
var prevState = this.state;
|
|
763
|
+
|
|
764
|
+
if (this.componentWillUpdate) {
|
|
765
|
+
this.componentWillUpdate(nextProps, nextState, transaction);
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
this.props = nextProps;
|
|
769
|
+
this.state = nextState;
|
|
770
|
+
|
|
771
|
+
this.updateComponent(transaction, prevProps, prevState);
|
|
772
|
+
|
|
773
|
+
if (this.componentDidUpdate) {
|
|
774
|
+
transaction.getReactMountReady().enqueue(
|
|
775
|
+
this,
|
|
776
|
+
this.componentDidUpdate.bind(this, prevProps, prevState)
|
|
777
|
+
);
|
|
778
|
+
}
|
|
779
|
+
},
|
|
780
|
+
|
|
781
|
+
/**
|
|
782
|
+
* Updates the component's currently mounted DOM representation.
|
|
783
|
+
*
|
|
784
|
+
* By default, this implements React's rendering and reconciliation algorithm.
|
|
785
|
+
* Sophisticated clients may wish to override this.
|
|
786
|
+
*
|
|
787
|
+
* @param {ReactReconcileTransaction} transaction
|
|
788
|
+
* @param {object} prevProps
|
|
789
|
+
* @param {?object} prevState
|
|
790
|
+
* @internal
|
|
791
|
+
* @overridable
|
|
792
|
+
*/
|
|
793
|
+
updateComponent: ReactPerf.measure(
|
|
794
|
+
'ReactCompositeComponent',
|
|
795
|
+
'updateComponent',
|
|
796
|
+
function(transaction, prevProps, prevState) {
|
|
797
|
+
ReactComponent.Mixin.updateComponent.call(this, transaction, prevProps);
|
|
798
|
+
var currentComponent = this._renderedComponent;
|
|
799
|
+
var nextComponent = this._renderValidatedComponent();
|
|
800
|
+
if (currentComponent.constructor === nextComponent.constructor) {
|
|
801
|
+
currentComponent.receiveComponent(nextComponent, transaction);
|
|
802
|
+
} else {
|
|
803
|
+
// These two IDs are actually the same! But nothing should rely on that.
|
|
804
|
+
var thisID = this._rootNodeID;
|
|
805
|
+
var currentComponentID = currentComponent._rootNodeID;
|
|
806
|
+
currentComponent.unmountComponent();
|
|
807
|
+
this._renderedComponent = nextComponent;
|
|
808
|
+
var nextMarkup = nextComponent.mountComponent(
|
|
809
|
+
thisID,
|
|
810
|
+
transaction,
|
|
811
|
+
this._mountDepth + 1
|
|
812
|
+
);
|
|
813
|
+
ReactComponent.DOMIDOperations.dangerouslyReplaceNodeWithMarkupByID(
|
|
814
|
+
currentComponentID,
|
|
815
|
+
nextMarkup
|
|
816
|
+
);
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
),
|
|
820
|
+
|
|
821
|
+
/**
|
|
822
|
+
* Forces an update. This should only be invoked when it is known with
|
|
823
|
+
* certainty that we are **not** in a DOM transaction.
|
|
824
|
+
*
|
|
825
|
+
* You may want to call this when you know that some deeper aspect of the
|
|
826
|
+
* component's state has changed but `setState` was not called.
|
|
827
|
+
*
|
|
828
|
+
* This will not invoke `shouldUpdateComponent`, but it will invoke
|
|
829
|
+
* `componentWillUpdate` and `componentDidUpdate`.
|
|
830
|
+
*
|
|
831
|
+
* @param {?function} callback Called after update is complete.
|
|
832
|
+
* @final
|
|
833
|
+
* @protected
|
|
834
|
+
*/
|
|
835
|
+
forceUpdate: function(callback) {
|
|
836
|
+
var compositeLifeCycleState = this._compositeLifeCycleState;
|
|
837
|
+
("production" !== process.env.NODE_ENV ? invariant(
|
|
838
|
+
this.isMounted() ||
|
|
839
|
+
compositeLifeCycleState === CompositeLifeCycle.MOUNTING,
|
|
840
|
+
'forceUpdate(...): Can only force an update on mounted or mounting ' +
|
|
841
|
+
'components.'
|
|
842
|
+
) : invariant(this.isMounted() ||
|
|
843
|
+
compositeLifeCycleState === CompositeLifeCycle.MOUNTING));
|
|
844
|
+
("production" !== process.env.NODE_ENV ? invariant(
|
|
845
|
+
compositeLifeCycleState !== CompositeLifeCycle.RECEIVING_STATE &&
|
|
846
|
+
compositeLifeCycleState !== CompositeLifeCycle.UNMOUNTING,
|
|
847
|
+
'forceUpdate(...): Cannot force an update while unmounting component ' +
|
|
848
|
+
'or during an existing state transition (such as within `render`).'
|
|
849
|
+
) : invariant(compositeLifeCycleState !== CompositeLifeCycle.RECEIVING_STATE &&
|
|
850
|
+
compositeLifeCycleState !== CompositeLifeCycle.UNMOUNTING));
|
|
851
|
+
this._pendingForceUpdate = true;
|
|
852
|
+
ReactUpdates.enqueueUpdate(this, callback);
|
|
853
|
+
},
|
|
854
|
+
|
|
855
|
+
/**
|
|
856
|
+
* @private
|
|
857
|
+
*/
|
|
858
|
+
_renderValidatedComponent: function() {
|
|
859
|
+
var renderedComponent;
|
|
860
|
+
ReactCurrentOwner.current = this;
|
|
861
|
+
try {
|
|
862
|
+
renderedComponent = this.render();
|
|
863
|
+
} catch (error) {
|
|
864
|
+
// IE8 requires `catch` in order to use `finally`.
|
|
865
|
+
throw error;
|
|
866
|
+
} finally {
|
|
867
|
+
ReactCurrentOwner.current = null;
|
|
868
|
+
}
|
|
869
|
+
("production" !== process.env.NODE_ENV ? invariant(
|
|
870
|
+
ReactComponent.isValidComponent(renderedComponent),
|
|
871
|
+
'%s.render(): A valid ReactComponent must be returned. You may have ' +
|
|
872
|
+
'returned null, undefined, an array, or some other invalid object.',
|
|
873
|
+
this.constructor.displayName || 'ReactCompositeComponent'
|
|
874
|
+
) : invariant(ReactComponent.isValidComponent(renderedComponent)));
|
|
875
|
+
return renderedComponent;
|
|
876
|
+
},
|
|
877
|
+
|
|
878
|
+
/**
|
|
879
|
+
* @private
|
|
880
|
+
*/
|
|
881
|
+
_bindAutoBindMethods: function() {
|
|
882
|
+
for (var autoBindKey in this.__reactAutoBindMap) {
|
|
883
|
+
if (!this.__reactAutoBindMap.hasOwnProperty(autoBindKey)) {
|
|
884
|
+
continue;
|
|
885
|
+
}
|
|
886
|
+
var method = this.__reactAutoBindMap[autoBindKey];
|
|
887
|
+
this[autoBindKey] = this._bindAutoBindMethod(ReactErrorUtils.guard(
|
|
888
|
+
method,
|
|
889
|
+
this.constructor.displayName + '.' + autoBindKey
|
|
890
|
+
));
|
|
891
|
+
}
|
|
892
|
+
},
|
|
893
|
+
|
|
894
|
+
/**
|
|
895
|
+
* Binds a method to the component.
|
|
896
|
+
*
|
|
897
|
+
* @param {function} method Method to be bound.
|
|
898
|
+
* @private
|
|
899
|
+
*/
|
|
900
|
+
_bindAutoBindMethod: function(method) {
|
|
901
|
+
var component = this;
|
|
902
|
+
var boundMethod = function() {
|
|
903
|
+
return method.apply(component, arguments);
|
|
904
|
+
};
|
|
905
|
+
if ("production" !== process.env.NODE_ENV) {
|
|
906
|
+
boundMethod.__reactBoundContext = component;
|
|
907
|
+
boundMethod.__reactBoundMethod = method;
|
|
908
|
+
boundMethod.__reactBoundArguments = null;
|
|
909
|
+
var componentName = component.constructor.displayName;
|
|
910
|
+
var _bind = boundMethod.bind;
|
|
911
|
+
boundMethod.bind = function(newThis) {
|
|
912
|
+
// User is trying to bind() an autobound method; we effectively will
|
|
913
|
+
// ignore the value of "this" that the user is trying to use, so
|
|
914
|
+
// let's warn.
|
|
915
|
+
if (newThis !== component && newThis !== null) {
|
|
916
|
+
console.warn(
|
|
917
|
+
'bind(): React component methods may only be bound to the ' +
|
|
918
|
+
'component instance. See ' + componentName
|
|
919
|
+
);
|
|
920
|
+
} else if (arguments.length === 1) {
|
|
921
|
+
console.warn(
|
|
922
|
+
'bind(): You are binding a component method to the component. ' +
|
|
923
|
+
'React does this for you automatically in a high-performance ' +
|
|
924
|
+
'way, so you can safely remove this call. See ' + componentName
|
|
925
|
+
);
|
|
926
|
+
return boundMethod;
|
|
927
|
+
}
|
|
928
|
+
var reboundMethod = _bind.apply(boundMethod, arguments);
|
|
929
|
+
reboundMethod.__reactBoundContext = component;
|
|
930
|
+
reboundMethod.__reactBoundMethod = method;
|
|
931
|
+
reboundMethod.__reactBoundArguments =
|
|
932
|
+
Array.prototype.slice.call(arguments, 1);
|
|
933
|
+
return reboundMethod;
|
|
934
|
+
};
|
|
935
|
+
}
|
|
936
|
+
return boundMethod;
|
|
937
|
+
}
|
|
938
|
+
};
|
|
939
|
+
|
|
940
|
+
var ReactCompositeComponentBase = function() {};
|
|
941
|
+
mixInto(ReactCompositeComponentBase, ReactComponent.Mixin);
|
|
942
|
+
mixInto(ReactCompositeComponentBase, ReactOwner.Mixin);
|
|
943
|
+
mixInto(ReactCompositeComponentBase, ReactPropTransferer.Mixin);
|
|
944
|
+
mixInto(ReactCompositeComponentBase, ReactCompositeComponentMixin);
|
|
945
|
+
|
|
946
|
+
/**
|
|
947
|
+
* Module for creating composite components.
|
|
948
|
+
*
|
|
949
|
+
* @class ReactCompositeComponent
|
|
950
|
+
* @extends ReactComponent
|
|
951
|
+
* @extends ReactOwner
|
|
952
|
+
* @extends ReactPropTransferer
|
|
953
|
+
*/
|
|
954
|
+
var ReactCompositeComponent = {
|
|
955
|
+
|
|
956
|
+
LifeCycle: CompositeLifeCycle,
|
|
957
|
+
|
|
958
|
+
Base: ReactCompositeComponentBase,
|
|
959
|
+
|
|
960
|
+
/**
|
|
961
|
+
* Creates a composite component class given a class specification.
|
|
962
|
+
*
|
|
963
|
+
* @param {object} spec Class specification (which must define `render`).
|
|
964
|
+
* @return {function} Component constructor function.
|
|
965
|
+
* @public
|
|
966
|
+
*/
|
|
967
|
+
createClass: function(spec) {
|
|
968
|
+
var Constructor = function() {};
|
|
969
|
+
Constructor.prototype = new ReactCompositeComponentBase();
|
|
970
|
+
Constructor.prototype.constructor = Constructor;
|
|
971
|
+
mixSpecIntoComponent(Constructor, spec);
|
|
972
|
+
|
|
973
|
+
("production" !== process.env.NODE_ENV ? invariant(
|
|
974
|
+
Constructor.prototype.render,
|
|
975
|
+
'createClass(...): Class specification must implement a `render` method.'
|
|
976
|
+
) : invariant(Constructor.prototype.render));
|
|
977
|
+
|
|
978
|
+
if ("production" !== process.env.NODE_ENV) {
|
|
979
|
+
if (Constructor.prototype.componentShouldUpdate) {
|
|
980
|
+
console.warn(
|
|
981
|
+
(spec.displayName || 'A component') + ' has a method called ' +
|
|
982
|
+
'componentShouldUpdate(). Did you mean shouldComponentUpdate()? ' +
|
|
983
|
+
'The name is phrased as a question because the function is ' +
|
|
984
|
+
'expected to return a value.'
|
|
985
|
+
);
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
// Reduce time spent doing lookups by setting these on the prototype.
|
|
990
|
+
for (var methodName in ReactCompositeComponentInterface) {
|
|
991
|
+
if (!Constructor.prototype[methodName]) {
|
|
992
|
+
Constructor.prototype[methodName] = null;
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
var ConvenienceConstructor = function(props, children) {
|
|
997
|
+
var instance = new Constructor();
|
|
998
|
+
instance.construct.apply(instance, arguments);
|
|
999
|
+
return instance;
|
|
1000
|
+
};
|
|
1001
|
+
ConvenienceConstructor.componentConstructor = Constructor;
|
|
1002
|
+
ConvenienceConstructor.originalSpec = spec;
|
|
1003
|
+
return ConvenienceConstructor;
|
|
1004
|
+
},
|
|
1005
|
+
|
|
1006
|
+
/**
|
|
1007
|
+
* Checks if a value is a valid component constructor.
|
|
1008
|
+
*
|
|
1009
|
+
* @param {*}
|
|
1010
|
+
* @return {boolean}
|
|
1011
|
+
* @public
|
|
1012
|
+
*/
|
|
1013
|
+
isValidClass: function(componentClass) {
|
|
1014
|
+
return componentClass instanceof Function &&
|
|
1015
|
+
'componentConstructor' in componentClass &&
|
|
1016
|
+
componentClass.componentConstructor instanceof Function;
|
|
1017
|
+
}
|
|
1018
|
+
};
|
|
1019
|
+
|
|
1020
|
+
module.exports = ReactCompositeComponent;
|