react 0.13.0-alpha.2 → 0.13.0-beta.1

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.
@@ -57,27 +57,36 @@ function autoGenerateWrapperClass(type) {
57
57
  }
58
58
 
59
59
  /**
60
- * Create an internal class for a specific tag.
60
+ * Get a composite component wrapper class for a specific tag.
61
61
  *
62
- * @param {string} tag The tag for which to create an internal instance.
63
- * @param {any} props The props passed to the instance constructor.
64
- * @return {ReactComponent} component The injected empty component.
62
+ * @param {ReactElement} element The tag for which to get the class.
63
+ * @return {function} The React class constructor function.
65
64
  */
66
- function createInstanceForTag(tag, props, parentType) {
65
+ function getComponentClassForElement(element) {
66
+ if (typeof element.type === 'function') {
67
+ return element.type;
68
+ }
69
+ var tag = element.type;
67
70
  var componentClass = tagToComponentClass[tag];
68
71
  if (componentClass == null) {
69
72
  tagToComponentClass[tag] = componentClass = autoGenerateWrapperClass(tag);
70
73
  }
71
- if (parentType === tag) {
72
- // Avoid recursion
73
- ("production" !== process.env.NODE_ENV ? invariant(
74
- genericComponentClass,
75
- 'There is no registered component for the tag %s',
76
- tag
77
- ) : invariant(genericComponentClass));
78
- return new genericComponentClass(tag, props);
79
- }
80
- return new componentClass(props);
74
+ return componentClass;
75
+ }
76
+
77
+ /**
78
+ * Get a native internal component class for a specific tag.
79
+ *
80
+ * @param {ReactElement} element The element to create.
81
+ * @return {function} The internal class constructor function.
82
+ */
83
+ function createInternalComponent(element) {
84
+ ("production" !== process.env.NODE_ENV ? invariant(
85
+ genericComponentClass,
86
+ 'There is no registered component for the tag %s',
87
+ element.type
88
+ ) : invariant(genericComponentClass));
89
+ return new genericComponentClass(element.type, element.props);
81
90
  }
82
91
 
83
92
  /**
@@ -97,7 +106,8 @@ function isTextComponent(component) {
97
106
  }
98
107
 
99
108
  var ReactNativeComponent = {
100
- createInstanceForTag: createInstanceForTag,
109
+ getComponentClassForElement: getComponentClassForElement,
110
+ createInternalComponent: createInternalComponent,
101
111
  createInstanceForText: createInstanceForText,
102
112
  isTextComponent: isTextComponent,
103
113
  injection: ReactNativeComponentInjection
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Copyright 2013-2014, Facebook, Inc.
3
+ * All rights reserved.
4
+ *
5
+ * This source code is licensed under the BSD-style license found in the
6
+ * LICENSE file in the root directory of this source tree. An additional grant
7
+ * of patent rights can be found in the PATENTS file in the same directory.
8
+ *
9
+ * @providesModule ReactReconciler
10
+ */
11
+
12
+ 'use strict';
13
+
14
+ var ReactRef = require("./ReactRef");
15
+ var ReactElementValidator = require("./ReactElementValidator");
16
+
17
+ /**
18
+ * Helper to call ReactRef.attachRefs with this composite component, split out
19
+ * to avoid allocations in the transaction mount-ready queue.
20
+ */
21
+ function attachRefs() {
22
+ ReactRef.attachRefs(this, this._currentElement);
23
+ }
24
+
25
+ var ReactReconciler = {
26
+
27
+ /**
28
+ * Initializes the component, renders markup, and registers event listeners.
29
+ *
30
+ * @param {ReactComponent} internalInstance
31
+ * @param {string} rootID DOM ID of the root node.
32
+ * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
33
+ * @return {?string} Rendered markup to be inserted into the DOM.
34
+ * @final
35
+ * @internal
36
+ */
37
+ mountComponent: function(internalInstance, rootID, transaction, context) {
38
+ var markup = internalInstance.mountComponent(rootID, transaction, context);
39
+ if ("production" !== process.env.NODE_ENV) {
40
+ ReactElementValidator.checkAndWarnForMutatedProps(
41
+ internalInstance._currentElement
42
+ );
43
+ }
44
+ transaction.getReactMountReady().enqueue(attachRefs, internalInstance);
45
+ return markup;
46
+ },
47
+
48
+ /**
49
+ * Releases any resources allocated by `mountComponent`.
50
+ *
51
+ * @final
52
+ * @internal
53
+ */
54
+ unmountComponent: function(internalInstance) {
55
+ ReactRef.detachRefs(internalInstance, internalInstance._currentElement);
56
+ internalInstance.unmountComponent();
57
+ },
58
+
59
+ /**
60
+ * Update a component using a new element.
61
+ *
62
+ * @param {ReactComponent} internalInstance
63
+ * @param {ReactElement} nextElement
64
+ * @param {ReactReconcileTransaction} transaction
65
+ * @param {object} context
66
+ * @internal
67
+ */
68
+ receiveComponent: function(
69
+ internalInstance, nextElement, transaction, context
70
+ ) {
71
+ var prevElement = internalInstance._currentElement;
72
+
73
+ if (nextElement === prevElement && nextElement._owner != null) {
74
+ // Since elements are immutable after the owner is rendered,
75
+ // we can do a cheap identity compare here to determine if this is a
76
+ // superfluous reconcile. It's possible for state to be mutable but such
77
+ // change should trigger an update of the owner which would recreate
78
+ // the element. We explicitly check for the existence of an owner since
79
+ // it's possible for an element created outside a composite to be
80
+ // deeply mutated and reused.
81
+ return;
82
+ }
83
+
84
+ if ("production" !== process.env.NODE_ENV) {
85
+ ReactElementValidator.checkAndWarnForMutatedProps(nextElement);
86
+ }
87
+
88
+ var refsChanged = ReactRef.shouldUpdateRefs(
89
+ this,
90
+ prevElement,
91
+ nextElement
92
+ );
93
+
94
+ if (refsChanged) {
95
+ ReactRef.detachRefs(internalInstance, prevElement);
96
+ }
97
+
98
+ internalInstance.receiveComponent(nextElement, transaction, context);
99
+
100
+ if (refsChanged) {
101
+ transaction.getReactMountReady().enqueue(attachRefs, internalInstance);
102
+ }
103
+ }
104
+
105
+ };
106
+
107
+ module.exports = ReactReconciler;
package/lib/ReactRef.js CHANGED
@@ -11,85 +11,59 @@
11
11
 
12
12
  'use strict';
13
13
 
14
+ var ReactOwner = require("./ReactOwner");
14
15
  var ReactUpdates = require("./ReactUpdates");
15
16
 
16
- var accumulate = require("./accumulate");
17
- var assign = require("./Object.assign");
18
- var forEachAccumulated = require("./forEachAccumulated");
19
- var invariant = require("./invariant");
17
+ var ReactRef = {};
20
18
 
21
- function ReactRef() {
22
- this._value = null;
23
- this._successCallbacks = null;
24
- this._failureCallbacks = null;
19
+ function attachRef(ref, component, owner) {
20
+ if (typeof ref === 'function') {
21
+ ref(component.getPublicInstance());
22
+ } else {
23
+ // Legacy ref
24
+ ReactOwner.addComponentAsRefTo(component, ref, owner);
25
+ }
25
26
  }
26
27
 
27
- /**
28
- * Call the enqueued success or failure callbacks for a ref, as appropriate.
29
- */
30
- function dispatchCallbacks() {
31
- /*jshint validthis:true */
32
- var successCallbacks = this._successCallbacks;
33
- var failureCallbacks = this._failureCallbacks;
34
- this._successCallbacks = null;
35
- this._failureCallbacks = null;
36
-
37
- if (this._value) {
38
- forEachAccumulated(successCallbacks, callSuccess, this);
28
+ function detachRef(ref, component, owner) {
29
+ if (typeof ref === 'function') {
30
+ ref(null);
39
31
  } else {
40
- forEachAccumulated(failureCallbacks, callFailure);
32
+ // Legacy ref
33
+ ReactOwner.removeComponentAsRefFrom(component, ref, owner);
41
34
  }
42
35
  }
43
36
 
44
- /**
45
- * Call a single success callback, passing the ref's value.
46
- */
47
- function callSuccess(cb) {
48
- /*jshint validthis:true */
49
- cb(this._value);
50
- }
37
+ ReactRef.attachRefs = function(instance, element) {
38
+ var ref = element.ref;
39
+ if (ref != null) {
40
+ attachRef(ref, instance, element._owner);
41
+ }
42
+ };
51
43
 
52
- /**
53
- * Call a single failure callback, passing no arguments.
54
- */
55
- function callFailure(cb) {
56
- cb();
57
- }
44
+ ReactRef.shouldUpdateRefs = function(instance, prevElement, nextElement) {
45
+ // If either the owner or a `ref` has changed, make sure the newest owner
46
+ // has stored a reference to `this`, and the previous owner (if different)
47
+ // has forgotten the reference to `this`. We use the element instead
48
+ // of the public this.props because the post processing cannot determine
49
+ // a ref. The ref conceptually lives on the element.
58
50
 
59
- assign(ReactRef.prototype, {
60
- /**
61
- * Get the value of a ref asynchronously. Accepts a success callback and an
62
- * optional failure callback. If the ref has been rendered, the success
63
- * callback will be called with the component instance; otherwise, the failure
64
- * callback will be executed.
65
- *
66
- * @param {function} success Callback in case of success
67
- * @param {?function} failure Callback in case of failure
68
- */
69
- then: function(success, failure) {
70
- ("production" !== process.env.NODE_ENV ? invariant(
71
- typeof success === 'function',
72
- 'ReactRef.then(...): Must provide a success callback.'
73
- ) : invariant(typeof success === 'function'));
74
- if (this._successCallbacks == null) {
75
- ReactUpdates.asap(dispatchCallbacks, this);
76
- }
77
- this._successCallbacks = accumulate(this._successCallbacks, success);
78
- if (failure) {
79
- this._failureCallbacks = accumulate(this._failureCallbacks, failure);
80
- }
81
- }
82
- });
51
+ // TODO: Should this even be possible? The owner cannot change because
52
+ // it's forbidden by shouldUpdateReactComponent. The ref can change
53
+ // if you swap the keys of but not the refs. Reconsider where this check
54
+ // is made. It probably belongs where the key checking and
55
+ // instantiateReactComponent is done.
83
56
 
84
- ReactRef.attachRef = function(ref, value) {
85
- ref._value = value.getPublicInstance();
57
+ return (
58
+ nextElement._owner !== prevElement._owner ||
59
+ nextElement.ref !== prevElement.ref
60
+ );
86
61
  };
87
62
 
88
- ReactRef.detachRef = function(ref, value) {
89
- // Check that `component` is still the current ref because we do not want to
90
- // detach the ref if another component stole it.
91
- if (ref._value === value) {
92
- ref._value = null;
63
+ ReactRef.detachRefs = function(instance, element) {
64
+ var ref = element.ref;
65
+ if (ref != null) {
66
+ detachRef(ref, instance, element._owner);
93
67
  }
94
68
  };
95
69
 
@@ -320,15 +320,44 @@ var ReactShallowRenderer = function() {
320
320
  };
321
321
 
322
322
  ReactShallowRenderer.prototype.getRenderOutput = function() {
323
- return (this._instance && this._instance._renderedComponent) || null;
323
+ return (
324
+ (this._instance && this._instance._renderedComponent &&
325
+ this._instance._renderedComponent._currentElement)
326
+ || null
327
+ );
324
328
  };
325
329
 
326
- var ShallowComponentWrapper = function(inst) {
327
- this._instance = inst;
330
+ var NoopInternalComponent = function(element) {
331
+ this._currentElement = element;
332
+ }
333
+
334
+ NoopInternalComponent.prototype = {
335
+
336
+ mountComponent: function() {
337
+ },
338
+
339
+ receiveComponent: function(element) {
340
+ this._currentElement = element;
341
+ },
342
+
343
+ unmountComponent: function() {
344
+
345
+ }
346
+
328
347
  };
348
+
349
+ var ShallowComponentWrapper = function() { };
329
350
  assign(
330
351
  ShallowComponentWrapper.prototype,
331
- ReactCompositeComponent.ShallowMixin
352
+ ReactCompositeComponent.Mixin, {
353
+ _instantiateReactComponent: function(element) {
354
+ return new NoopInternalComponent(element);
355
+ },
356
+ _replaceNodeWithMarkupByID: function() {},
357
+ _renderValidatedComponent:
358
+ ReactCompositeComponent.Mixin.
359
+ _renderValidatedComponentWithoutOwnerOrContext
360
+ }
332
361
  );
333
362
 
334
363
  ReactShallowRenderer.prototype.render = function(element, context) {
@@ -340,7 +369,7 @@ ReactShallowRenderer.prototype.render = function(element, context) {
340
369
  ReactShallowRenderer.prototype._render = function(element, transaction, context) {
341
370
  if (!this._instance) {
342
371
  var rootID = ReactInstanceHandles.createReactRootID();
343
- var instance = new ShallowComponentWrapper(new element.type(element.props));
372
+ var instance = new ShallowComponentWrapper(element.type);
344
373
  instance.construct(element);
345
374
 
346
375
  instance.mountComponent(rootID, transaction, context);
@@ -0,0 +1,264 @@
1
+ /**
2
+ * Copyright 2015, Facebook, Inc.
3
+ * All rights reserved.
4
+ *
5
+ * This source code is licensed under the BSD-style license found in the
6
+ * LICENSE file in the root directory of this source tree. An additional grant
7
+ * of patent rights can be found in the PATENTS file in the same directory.
8
+ *
9
+ * @providesModule ReactUpdateQueue
10
+ */
11
+
12
+ "use strict";
13
+
14
+ var ReactLifeCycle = require("./ReactLifeCycle");
15
+ var ReactCurrentOwner = require("./ReactCurrentOwner");
16
+ var ReactElement = require("./ReactElement");
17
+ var ReactInstanceMap = require("./ReactInstanceMap");
18
+ var ReactUpdates = require("./ReactUpdates");
19
+
20
+ var assign = require("./Object.assign");
21
+ var invariant = require("./invariant");
22
+
23
+ function enqueueUpdate(internalInstance) {
24
+ if (internalInstance !== ReactLifeCycle.currentlyMountingInstance) {
25
+ // If we're in a componentWillMount handler, don't enqueue a rerender
26
+ // because ReactUpdates assumes we're in a browser context (which is
27
+ // wrong for server rendering) and we're about to do a render anyway.
28
+ // See bug in #1740.
29
+ ReactUpdates.enqueueUpdate(internalInstance);
30
+ }
31
+ }
32
+
33
+ function getInternalInstanceReadyForUpdate(publicInstance, callerName) {
34
+ ("production" !== process.env.NODE_ENV ? invariant(
35
+ ReactCurrentOwner.current == null,
36
+ '%s(...): Cannot update during an existing state transition ' +
37
+ '(such as within `render`). Render methods should be a pure function ' +
38
+ 'of props and state.',
39
+ callerName
40
+ ) : invariant(ReactCurrentOwner.current == null));
41
+
42
+ var internalInstance = ReactInstanceMap.get(publicInstance);
43
+ ("production" !== process.env.NODE_ENV ? invariant(
44
+ internalInstance,
45
+ '%s(...): Can only update a mounted or mounting component. ' +
46
+ 'This usually means you called %s() on an unmounted ' +
47
+ 'component.',
48
+ callerName,
49
+ callerName
50
+ ) : invariant(internalInstance));
51
+ ("production" !== process.env.NODE_ENV ? invariant(
52
+ internalInstance !== ReactLifeCycle.currentlyUnmountingInstance,
53
+ '%s(...): Cannot call %s() on an unmounting component.',
54
+ callerName,
55
+ callerName
56
+ ) : invariant(internalInstance !== ReactLifeCycle.currentlyUnmountingInstance));
57
+ return internalInstance;
58
+ }
59
+
60
+ /**
61
+ * ReactUpdateQueue allows for state updates to be scheduled into a later
62
+ * reconciliation step.
63
+ */
64
+ var ReactUpdateQueue = {
65
+
66
+ /**
67
+ * Enqueue a callback that will be executed after all the pending updates
68
+ * have processed.
69
+ *
70
+ * @param {ReactClass} publicInstance The instance to use as `this` context.
71
+ * @param {?function} callback Called after state is updated.
72
+ * @internal
73
+ */
74
+ enqueueCallback: function(publicInstance, callback) {
75
+ ("production" !== process.env.NODE_ENV ? invariant(
76
+ typeof callback === 'function',
77
+ 'enqueueCallback(...): You called `setProps`, `replaceProps`, ' +
78
+ '`setState`, `replaceState`, or `forceUpdate` with a callback that ' +
79
+ 'isn\'t callable.'
80
+ ) : invariant(typeof callback === 'function'));
81
+ var internalInstance = ReactInstanceMap.get(publicInstance);
82
+ ("production" !== process.env.NODE_ENV ? invariant(
83
+ internalInstance,
84
+ 'Cannot enqueue a callback on an instance that is unmounted.'
85
+ ) : invariant(internalInstance));
86
+ if (internalInstance === ReactLifeCycle.currentlyMountingInstance) {
87
+ // Ignore callbacks in componentWillMount. See enqueueUpdate.
88
+ return;
89
+ }
90
+ if (internalInstance._pendingCallbacks) {
91
+ internalInstance._pendingCallbacks.push(callback);
92
+ } else {
93
+ internalInstance._pendingCallbacks = [callback];
94
+ }
95
+ // TODO: The callback here is ignored when setState is called from
96
+ // componentWillMount. Either fix it or disallow doing so completely in
97
+ // favor of getInitialState. Alternatively, we can disallow
98
+ // componentWillMount during server-side rendering.
99
+ enqueueUpdate(internalInstance);
100
+ },
101
+
102
+ enqueueCallbackInternal: function(internalInstance, callback) {
103
+ ("production" !== process.env.NODE_ENV ? invariant(
104
+ typeof callback === "function",
105
+ 'enqueueCallback(...): You called `setProps`, `replaceProps`, ' +
106
+ '`setState`, `replaceState`, or `forceUpdate` with a callback that ' +
107
+ 'isn\'t callable.'
108
+ ) : invariant(typeof callback === "function"));
109
+ if (internalInstance._pendingCallbacks) {
110
+ internalInstance._pendingCallbacks.push(callback);
111
+ } else {
112
+ internalInstance._pendingCallbacks = [callback];
113
+ }
114
+ },
115
+
116
+ /**
117
+ * Forces an update. This should only be invoked when it is known with
118
+ * certainty that we are **not** in a DOM transaction.
119
+ *
120
+ * You may want to call this when you know that some deeper aspect of the
121
+ * component's state has changed but `setState` was not called.
122
+ *
123
+ * This will not invoke `shouldUpdateComponent`, but it will invoke
124
+ * `componentWillUpdate` and `componentDidUpdate`.
125
+ *
126
+ * @param {ReactClass} publicInstance The instance that should rerender.
127
+ * @internal
128
+ */
129
+ enqueueForceUpdate: function(publicInstance) {
130
+ var internalInstance = getInternalInstanceReadyForUpdate(
131
+ publicInstance,
132
+ 'forceUpdate'
133
+ );
134
+
135
+ internalInstance._pendingForceUpdate = true;
136
+
137
+ enqueueUpdate(internalInstance);
138
+ },
139
+
140
+ /**
141
+ * Replaces all of the state. Always use this or `setState` to mutate state.
142
+ * You should treat `this.state` as immutable.
143
+ *
144
+ * There is no guarantee that `this.state` will be immediately updated, so
145
+ * accessing `this.state` after calling this method may return the old value.
146
+ *
147
+ * @param {ReactClass} publicInstance The instance that should rerender.
148
+ * @param {object} completeState Next state.
149
+ * @internal
150
+ */
151
+ enqueueReplaceState: function(publicInstance, completeState) {
152
+ var internalInstance = getInternalInstanceReadyForUpdate(
153
+ publicInstance,
154
+ 'replaceState'
155
+ );
156
+
157
+ internalInstance._pendingState = completeState;
158
+
159
+ enqueueUpdate(internalInstance);
160
+ },
161
+
162
+ /**
163
+ * Sets a subset of the state. This only exists because _pendingState is
164
+ * internal. This provides a merging strategy that is not available to deep
165
+ * properties which is confusing. TODO: Expose pendingState or don't use it
166
+ * during the merge.
167
+ *
168
+ * @param {ReactClass} publicInstance The instance that should rerender.
169
+ * @param {object} partialState Next partial state to be merged with state.
170
+ * @internal
171
+ */
172
+ enqueueSetState: function(publicInstance, partialState) {
173
+ var internalInstance = getInternalInstanceReadyForUpdate(
174
+ publicInstance,
175
+ 'setState'
176
+ );
177
+
178
+ // Merge with `_pendingState` if it exists, otherwise with existing state.
179
+ internalInstance._pendingState = assign(
180
+ {},
181
+ internalInstance._pendingState || internalInstance._instance.state,
182
+ partialState
183
+ );
184
+
185
+ enqueueUpdate(internalInstance);
186
+ },
187
+
188
+ /**
189
+ * Sets a subset of the props.
190
+ *
191
+ * @param {ReactClass} publicInstance The instance that should rerender.
192
+ * @param {object} partialProps Subset of the next props.
193
+ * @internal
194
+ */
195
+ enqueueSetProps: function(publicInstance, partialProps) {
196
+ var internalInstance = getInternalInstanceReadyForUpdate(
197
+ publicInstance,
198
+ 'setProps'
199
+ );
200
+
201
+ ("production" !== process.env.NODE_ENV ? invariant(
202
+ internalInstance._isTopLevel,
203
+ 'setProps(...): You called `setProps` on a ' +
204
+ 'component with a parent. This is an anti-pattern since props will ' +
205
+ 'get reactively updated when rendered. Instead, change the owner\'s ' +
206
+ '`render` method to pass the correct value as props to the component ' +
207
+ 'where it is created.'
208
+ ) : invariant(internalInstance._isTopLevel));
209
+
210
+ // Merge with the pending element if it exists, otherwise with existing
211
+ // element props.
212
+ var element = internalInstance._pendingElement ||
213
+ internalInstance._currentElement;
214
+ var props = assign({}, element.props, partialProps);
215
+ internalInstance._pendingElement = ReactElement.cloneAndReplaceProps(
216
+ element,
217
+ props
218
+ );
219
+
220
+ enqueueUpdate(internalInstance);
221
+ },
222
+
223
+ /**
224
+ * Replaces all of the props.
225
+ *
226
+ * @param {ReactClass} publicInstance The instance that should rerender.
227
+ * @param {object} props New props.
228
+ * @internal
229
+ */
230
+ enqueueReplaceProps: function(publicInstance, props) {
231
+ var internalInstance = getInternalInstanceReadyForUpdate(
232
+ publicInstance,
233
+ 'replaceProps'
234
+ );
235
+
236
+ ("production" !== process.env.NODE_ENV ? invariant(
237
+ internalInstance._isTopLevel,
238
+ 'replaceProps(...): You called `replaceProps` on a ' +
239
+ 'component with a parent. This is an anti-pattern since props will ' +
240
+ 'get reactively updated when rendered. Instead, change the owner\'s ' +
241
+ '`render` method to pass the correct value as props to the component ' +
242
+ 'where it is created.'
243
+ ) : invariant(internalInstance._isTopLevel));
244
+
245
+ // Merge with the pending element if it exists, otherwise with existing
246
+ // element props.
247
+ var element = internalInstance._pendingElement ||
248
+ internalInstance._currentElement;
249
+ internalInstance._pendingElement = ReactElement.cloneAndReplaceProps(
250
+ element,
251
+ props
252
+ );
253
+
254
+ enqueueUpdate(internalInstance);
255
+ },
256
+
257
+ enqueueElementInternal: function(internalInstance, newElement) {
258
+ internalInstance._pendingElement = newElement;
259
+ enqueueUpdate(internalInstance);
260
+ }
261
+
262
+ };
263
+
264
+ module.exports = ReactUpdateQueue;