UNPKG

26.5 kBJavaScriptView Raw
1/**
2 * Copyright 2013-present, 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 */
10
11'use strict';
12
13var _prodInvariant = require('./reactProdInvariant'),
14 _assign = require('object-assign');
15
16var ReactComponent = require('./ReactComponent');
17var ReactElement = require('./ReactElement');
18var ReactPropTypeLocationNames = require('./ReactPropTypeLocationNames');
19var ReactNoopUpdateQueue = require('./ReactNoopUpdateQueue');
20
21var emptyObject = require('fbjs/lib/emptyObject');
22var invariant = require('fbjs/lib/invariant');
23var warning = require('fbjs/lib/warning');
24
25var MIXINS_KEY = 'mixins';
26
27// Helper function to allow the creation of anonymous functions which do not
28// have .name set to the name of the variable being assigned to.
29function identity(fn) {
30 return fn;
31}
32
33/**
34 * Policies that describe methods in `ReactClassInterface`.
35 */
36
37
38var injectedMixins = [];
39
40/**
41 * Composite components are higher-level components that compose other composite
42 * or host components.
43 *
44 * To create a new type of `ReactClass`, pass a specification of
45 * your new class to `React.createClass`. The only requirement of your class
46 * specification is that you implement a `render` method.
47 *
48 * var MyComponent = React.createClass({
49 * render: function() {
50 * return <div>Hello World</div>;
51 * }
52 * });
53 *
54 * The class specification supports a specific protocol of methods that have
55 * special meaning (e.g. `render`). See `ReactClassInterface` for
56 * more the comprehensive protocol. Any other properties and methods in the
57 * class specification will be available on the prototype.
58 *
59 * @interface ReactClassInterface
60 * @internal
61 */
62var ReactClassInterface = {
63
64 /**
65 * An array of Mixin objects to include when defining your component.
66 *
67 * @type {array}
68 * @optional
69 */
70 mixins: 'DEFINE_MANY',
71
72 /**
73 * An object containing properties and methods that should be defined on
74 * the component's constructor instead of its prototype (static methods).
75 *
76 * @type {object}
77 * @optional
78 */
79 statics: 'DEFINE_MANY',
80
81 /**
82 * Definition of prop types for this component.
83 *
84 * @type {object}
85 * @optional
86 */
87 propTypes: 'DEFINE_MANY',
88
89 /**
90 * Definition of context types for this component.
91 *
92 * @type {object}
93 * @optional
94 */
95 contextTypes: 'DEFINE_MANY',
96
97 /**
98 * Definition of context types this component sets for its children.
99 *
100 * @type {object}
101 * @optional
102 */
103 childContextTypes: 'DEFINE_MANY',
104
105 // ==== Definition methods ====
106
107 /**
108 * Invoked when the component is mounted. Values in the mapping will be set on
109 * `this.props` if that prop is not specified (i.e. using an `in` check).
110 *
111 * This method is invoked before `getInitialState` and therefore cannot rely
112 * on `this.state` or use `this.setState`.
113 *
114 * @return {object}
115 * @optional
116 */
117 getDefaultProps: 'DEFINE_MANY_MERGED',
118
119 /**
120 * Invoked once before the component is mounted. The return value will be used
121 * as the initial value of `this.state`.
122 *
123 * getInitialState: function() {
124 * return {
125 * isOn: false,
126 * fooBaz: new BazFoo()
127 * }
128 * }
129 *
130 * @return {object}
131 * @optional
132 */
133 getInitialState: 'DEFINE_MANY_MERGED',
134
135 /**
136 * @return {object}
137 * @optional
138 */
139 getChildContext: 'DEFINE_MANY_MERGED',
140
141 /**
142 * Uses props from `this.props` and state from `this.state` to render the
143 * structure of the component.
144 *
145 * No guarantees are made about when or how often this method is invoked, so
146 * it must not have side effects.
147 *
148 * render: function() {
149 * var name = this.props.name;
150 * return <div>Hello, {name}!</div>;
151 * }
152 *
153 * @return {ReactComponent}
154 * @nosideeffects
155 * @required
156 */
157 render: 'DEFINE_ONCE',
158
159 // ==== Delegate methods ====
160
161 /**
162 * Invoked when the component is initially created and about to be mounted.
163 * This may have side effects, but any external subscriptions or data created
164 * by this method must be cleaned up in `componentWillUnmount`.
165 *
166 * @optional
167 */
168 componentWillMount: 'DEFINE_MANY',
169
170 /**
171 * Invoked when the component has been mounted and has a DOM representation.
172 * However, there is no guarantee that the DOM node is in the document.
173 *
174 * Use this as an opportunity to operate on the DOM when the component has
175 * been mounted (initialized and rendered) for the first time.
176 *
177 * @param {DOMElement} rootNode DOM element representing the component.
178 * @optional
179 */
180 componentDidMount: 'DEFINE_MANY',
181
182 /**
183 * Invoked before the component receives new props.
184 *
185 * Use this as an opportunity to react to a prop transition by updating the
186 * state using `this.setState`. Current props are accessed via `this.props`.
187 *
188 * componentWillReceiveProps: function(nextProps, nextContext) {
189 * this.setState({
190 * likesIncreasing: nextProps.likeCount > this.props.likeCount
191 * });
192 * }
193 *
194 * NOTE: There is no equivalent `componentWillReceiveState`. An incoming prop
195 * transition may cause a state change, but the opposite is not true. If you
196 * need it, you are probably looking for `componentWillUpdate`.
197 *
198 * @param {object} nextProps
199 * @optional
200 */
201 componentWillReceiveProps: 'DEFINE_MANY',
202
203 /**
204 * Invoked while deciding if the component should be updated as a result of
205 * receiving new props, state and/or context.
206 *
207 * Use this as an opportunity to `return false` when you're certain that the
208 * transition to the new props/state/context will not require a component
209 * update.
210 *
211 * shouldComponentUpdate: function(nextProps, nextState, nextContext) {
212 * return !equal(nextProps, this.props) ||
213 * !equal(nextState, this.state) ||
214 * !equal(nextContext, this.context);
215 * }
216 *
217 * @param {object} nextProps
218 * @param {?object} nextState
219 * @param {?object} nextContext
220 * @return {boolean} True if the component should update.
221 * @optional
222 */
223 shouldComponentUpdate: 'DEFINE_ONCE',
224
225 /**
226 * Invoked when the component is about to update due to a transition from
227 * `this.props`, `this.state` and `this.context` to `nextProps`, `nextState`
228 * and `nextContext`.
229 *
230 * Use this as an opportunity to perform preparation before an update occurs.
231 *
232 * NOTE: You **cannot** use `this.setState()` in this method.
233 *
234 * @param {object} nextProps
235 * @param {?object} nextState
236 * @param {?object} nextContext
237 * @param {ReactReconcileTransaction} transaction
238 * @optional
239 */
240 componentWillUpdate: 'DEFINE_MANY',
241
242 /**
243 * Invoked when the component's DOM representation has been updated.
244 *
245 * Use this as an opportunity to operate on the DOM when the component has
246 * been updated.
247 *
248 * @param {object} prevProps
249 * @param {?object} prevState
250 * @param {?object} prevContext
251 * @param {DOMElement} rootNode DOM element representing the component.
252 * @optional
253 */
254 componentDidUpdate: 'DEFINE_MANY',
255
256 /**
257 * Invoked when the component is about to be removed from its parent and have
258 * its DOM representation destroyed.
259 *
260 * Use this as an opportunity to deallocate any external resources.
261 *
262 * NOTE: There is no `componentDidUnmount` since your component will have been
263 * destroyed by that point.
264 *
265 * @optional
266 */
267 componentWillUnmount: 'DEFINE_MANY',
268
269 // ==== Advanced methods ====
270
271 /**
272 * Updates the component's currently mounted DOM representation.
273 *
274 * By default, this implements React's rendering and reconciliation algorithm.
275 * Sophisticated clients may wish to override this.
276 *
277 * @param {ReactReconcileTransaction} transaction
278 * @internal
279 * @overridable
280 */
281 updateComponent: 'OVERRIDE_BASE'
282
283};
284
285/**
286 * Mapping from class specification keys to special processing functions.
287 *
288 * Although these are declared like instance properties in the specification
289 * when defining classes using `React.createClass`, they are actually static
290 * and are accessible on the constructor instead of the prototype. Despite
291 * being static, they must be defined outside of the "statics" key under
292 * which all other static methods are defined.
293 */
294var RESERVED_SPEC_KEYS = {
295 displayName: function (Constructor, displayName) {
296 Constructor.displayName = displayName;
297 },
298 mixins: function (Constructor, mixins) {
299 if (mixins) {
300 for (var i = 0; i < mixins.length; i++) {
301 mixSpecIntoComponent(Constructor, mixins[i]);
302 }
303 }
304 },
305 childContextTypes: function (Constructor, childContextTypes) {
306 if (process.env.NODE_ENV !== 'production') {
307 validateTypeDef(Constructor, childContextTypes, 'childContext');
308 }
309 Constructor.childContextTypes = _assign({}, Constructor.childContextTypes, childContextTypes);
310 },
311 contextTypes: function (Constructor, contextTypes) {
312 if (process.env.NODE_ENV !== 'production') {
313 validateTypeDef(Constructor, contextTypes, 'context');
314 }
315 Constructor.contextTypes = _assign({}, Constructor.contextTypes, contextTypes);
316 },
317 /**
318 * Special case getDefaultProps which should move into statics but requires
319 * automatic merging.
320 */
321 getDefaultProps: function (Constructor, getDefaultProps) {
322 if (Constructor.getDefaultProps) {
323 Constructor.getDefaultProps = createMergedResultFunction(Constructor.getDefaultProps, getDefaultProps);
324 } else {
325 Constructor.getDefaultProps = getDefaultProps;
326 }
327 },
328 propTypes: function (Constructor, propTypes) {
329 if (process.env.NODE_ENV !== 'production') {
330 validateTypeDef(Constructor, propTypes, 'prop');
331 }
332 Constructor.propTypes = _assign({}, Constructor.propTypes, propTypes);
333 },
334 statics: function (Constructor, statics) {
335 mixStaticSpecIntoComponent(Constructor, statics);
336 },
337 autobind: function () {} };
338
339function validateTypeDef(Constructor, typeDef, location) {
340 for (var propName in typeDef) {
341 if (typeDef.hasOwnProperty(propName)) {
342 // use a warning instead of an invariant so components
343 // don't show up in prod but only in __DEV__
344 process.env.NODE_ENV !== 'production' ? warning(typeof typeDef[propName] === 'function', '%s: %s type `%s` is invalid; it must be a function, usually from ' + 'React.PropTypes.', Constructor.displayName || 'ReactClass', ReactPropTypeLocationNames[location], propName) : void 0;
345 }
346 }
347}
348
349function validateMethodOverride(isAlreadyDefined, name) {
350 var specPolicy = ReactClassInterface.hasOwnProperty(name) ? ReactClassInterface[name] : null;
351
352 // Disallow overriding of base class methods unless explicitly allowed.
353 if (ReactClassMixin.hasOwnProperty(name)) {
354 !(specPolicy === 'OVERRIDE_BASE') ? process.env.NODE_ENV !== 'production' ? invariant(false, 'ReactClassInterface: You are attempting to override `%s` from your class specification. Ensure that your method names do not overlap with React methods.', name) : _prodInvariant('73', name) : void 0;
355 }
356
357 // Disallow defining methods more than once unless explicitly allowed.
358 if (isAlreadyDefined) {
359 !(specPolicy === 'DEFINE_MANY' || specPolicy === 'DEFINE_MANY_MERGED') ? process.env.NODE_ENV !== 'production' ? invariant(false, 'ReactClassInterface: You are attempting to define `%s` on your component more than once. This conflict may be due to a mixin.', name) : _prodInvariant('74', name) : void 0;
360 }
361}
362
363/**
364 * Mixin helper which handles policy validation and reserved
365 * specification keys when building React classes.
366 */
367function mixSpecIntoComponent(Constructor, spec) {
368 if (!spec) {
369 if (process.env.NODE_ENV !== 'production') {
370 var typeofSpec = typeof spec;
371 var isMixinValid = typeofSpec === 'object' && spec !== null;
372
373 process.env.NODE_ENV !== 'production' ? warning(isMixinValid, '%s: You\'re attempting to include a mixin that is either null ' + 'or not an object. Check the mixins included by the component, ' + 'as well as any mixins they include themselves. ' + 'Expected object but got %s.', Constructor.displayName || 'ReactClass', spec === null ? null : typeofSpec) : void 0;
374 }
375
376 return;
377 }
378
379 !(typeof spec !== 'function') ? process.env.NODE_ENV !== 'production' ? invariant(false, 'ReactClass: You\'re attempting to use a component class or function as a mixin. Instead, just use a regular object.') : _prodInvariant('75') : void 0;
380 !!ReactElement.isValidElement(spec) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'ReactClass: You\'re attempting to use a component as a mixin. Instead, just use a regular object.') : _prodInvariant('76') : void 0;
381
382 var proto = Constructor.prototype;
383 var autoBindPairs = proto.__reactAutoBindPairs;
384
385 // By handling mixins before any other properties, we ensure the same
386 // chaining order is applied to methods with DEFINE_MANY policy, whether
387 // mixins are listed before or after these methods in the spec.
388 if (spec.hasOwnProperty(MIXINS_KEY)) {
389 RESERVED_SPEC_KEYS.mixins(Constructor, spec.mixins);
390 }
391
392 for (var name in spec) {
393 if (!spec.hasOwnProperty(name)) {
394 continue;
395 }
396
397 if (name === MIXINS_KEY) {
398 // We have already handled mixins in a special case above.
399 continue;
400 }
401
402 var property = spec[name];
403 var isAlreadyDefined = proto.hasOwnProperty(name);
404 validateMethodOverride(isAlreadyDefined, name);
405
406 if (RESERVED_SPEC_KEYS.hasOwnProperty(name)) {
407 RESERVED_SPEC_KEYS[name](Constructor, property);
408 } else {
409 // Setup methods on prototype:
410 // The following member methods should not be automatically bound:
411 // 1. Expected ReactClass methods (in the "interface").
412 // 2. Overridden methods (that were mixed in).
413 var isReactClassMethod = ReactClassInterface.hasOwnProperty(name);
414 var isFunction = typeof property === 'function';
415 var shouldAutoBind = isFunction && !isReactClassMethod && !isAlreadyDefined && spec.autobind !== false;
416
417 if (shouldAutoBind) {
418 autoBindPairs.push(name, property);
419 proto[name] = property;
420 } else {
421 if (isAlreadyDefined) {
422 var specPolicy = ReactClassInterface[name];
423
424 // These cases should already be caught by validateMethodOverride.
425 !(isReactClassMethod && (specPolicy === 'DEFINE_MANY_MERGED' || specPolicy === 'DEFINE_MANY')) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'ReactClass: Unexpected spec policy %s for key %s when mixing in component specs.', specPolicy, name) : _prodInvariant('77', specPolicy, name) : void 0;
426
427 // For methods which are defined more than once, call the existing
428 // methods before calling the new property, merging if appropriate.
429 if (specPolicy === 'DEFINE_MANY_MERGED') {
430 proto[name] = createMergedResultFunction(proto[name], property);
431 } else if (specPolicy === 'DEFINE_MANY') {
432 proto[name] = createChainedFunction(proto[name], property);
433 }
434 } else {
435 proto[name] = property;
436 if (process.env.NODE_ENV !== 'production') {
437 // Add verbose displayName to the function, which helps when looking
438 // at profiling tools.
439 if (typeof property === 'function' && spec.displayName) {
440 proto[name].displayName = spec.displayName + '_' + name;
441 }
442 }
443 }
444 }
445 }
446 }
447}
448
449function mixStaticSpecIntoComponent(Constructor, statics) {
450 if (!statics) {
451 return;
452 }
453 for (var name in statics) {
454 var property = statics[name];
455 if (!statics.hasOwnProperty(name)) {
456 continue;
457 }
458
459 var isReserved = name in RESERVED_SPEC_KEYS;
460 !!isReserved ? process.env.NODE_ENV !== 'production' ? invariant(false, 'ReactClass: You are attempting to define a reserved property, `%s`, that shouldn\'t be on the "statics" key. Define it as an instance property instead; it will still be accessible on the constructor.', name) : _prodInvariant('78', name) : void 0;
461
462 var isInherited = name in Constructor;
463 !!isInherited ? process.env.NODE_ENV !== 'production' ? invariant(false, 'ReactClass: You are attempting to define `%s` on your component more than once. This conflict may be due to a mixin.', name) : _prodInvariant('79', name) : void 0;
464 Constructor[name] = property;
465 }
466}
467
468/**
469 * Merge two objects, but throw if both contain the same key.
470 *
471 * @param {object} one The first object, which is mutated.
472 * @param {object} two The second object
473 * @return {object} one after it has been mutated to contain everything in two.
474 */
475function mergeIntoWithNoDuplicateKeys(one, two) {
476 !(one && two && typeof one === 'object' && typeof two === 'object') ? process.env.NODE_ENV !== 'production' ? invariant(false, 'mergeIntoWithNoDuplicateKeys(): Cannot merge non-objects.') : _prodInvariant('80') : void 0;
477
478 for (var key in two) {
479 if (two.hasOwnProperty(key)) {
480 !(one[key] === undefined) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'mergeIntoWithNoDuplicateKeys(): Tried to merge two objects with the same key: `%s`. This conflict may be due to a mixin; in particular, this may be caused by two getInitialState() or getDefaultProps() methods returning objects with clashing keys.', key) : _prodInvariant('81', key) : void 0;
481 one[key] = two[key];
482 }
483 }
484 return one;
485}
486
487/**
488 * Creates a function that invokes two functions and merges their return values.
489 *
490 * @param {function} one Function to invoke first.
491 * @param {function} two Function to invoke second.
492 * @return {function} Function that invokes the two argument functions.
493 * @private
494 */
495function createMergedResultFunction(one, two) {
496 return function mergedResult() {
497 var a = one.apply(this, arguments);
498 var b = two.apply(this, arguments);
499 if (a == null) {
500 return b;
501 } else if (b == null) {
502 return a;
503 }
504 var c = {};
505 mergeIntoWithNoDuplicateKeys(c, a);
506 mergeIntoWithNoDuplicateKeys(c, b);
507 return c;
508 };
509}
510
511/**
512 * Creates a function that invokes two functions and ignores their return vales.
513 *
514 * @param {function} one Function to invoke first.
515 * @param {function} two Function to invoke second.
516 * @return {function} Function that invokes the two argument functions.
517 * @private
518 */
519function createChainedFunction(one, two) {
520 return function chainedFunction() {
521 one.apply(this, arguments);
522 two.apply(this, arguments);
523 };
524}
525
526/**
527 * Binds a method to the component.
528 *
529 * @param {object} component Component whose method is going to be bound.
530 * @param {function} method Method to be bound.
531 * @return {function} The bound method.
532 */
533function bindAutoBindMethod(component, method) {
534 var boundMethod = method.bind(component);
535 if (process.env.NODE_ENV !== 'production') {
536 boundMethod.__reactBoundContext = component;
537 boundMethod.__reactBoundMethod = method;
538 boundMethod.__reactBoundArguments = null;
539 var componentName = component.constructor.displayName;
540 var _bind = boundMethod.bind;
541 boundMethod.bind = function (newThis) {
542 for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
543 args[_key - 1] = arguments[_key];
544 }
545
546 // User is trying to bind() an autobound method; we effectively will
547 // ignore the value of "this" that the user is trying to use, so
548 // let's warn.
549 if (newThis !== component && newThis !== null) {
550 process.env.NODE_ENV !== 'production' ? warning(false, 'bind(): React component methods may only be bound to the ' + 'component instance. See %s', componentName) : void 0;
551 } else if (!args.length) {
552 process.env.NODE_ENV !== 'production' ? warning(false, 'bind(): You are binding a component method to the component. ' + 'React does this for you automatically in a high-performance ' + 'way, so you can safely remove this call. See %s', componentName) : void 0;
553 return boundMethod;
554 }
555 var reboundMethod = _bind.apply(boundMethod, arguments);
556 reboundMethod.__reactBoundContext = component;
557 reboundMethod.__reactBoundMethod = method;
558 reboundMethod.__reactBoundArguments = args;
559 return reboundMethod;
560 };
561 }
562 return boundMethod;
563}
564
565/**
566 * Binds all auto-bound methods in a component.
567 *
568 * @param {object} component Component whose method is going to be bound.
569 */
570function bindAutoBindMethods(component) {
571 var pairs = component.__reactAutoBindPairs;
572 for (var i = 0; i < pairs.length; i += 2) {
573 var autoBindKey = pairs[i];
574 var method = pairs[i + 1];
575 component[autoBindKey] = bindAutoBindMethod(component, method);
576 }
577}
578
579/**
580 * Add more to the ReactClass base class. These are all legacy features and
581 * therefore not already part of the modern ReactComponent.
582 */
583var ReactClassMixin = {
584
585 /**
586 * TODO: This will be deprecated because state should always keep a consistent
587 * type signature and the only use case for this, is to avoid that.
588 */
589 replaceState: function (newState, callback) {
590 this.updater.enqueueReplaceState(this, newState);
591 if (callback) {
592 this.updater.enqueueCallback(this, callback, 'replaceState');
593 }
594 },
595
596 /**
597 * Checks whether or not this composite component is mounted.
598 * @return {boolean} True if mounted, false otherwise.
599 * @protected
600 * @final
601 */
602 isMounted: function () {
603 return this.updater.isMounted(this);
604 }
605};
606
607var ReactClassComponent = function () {};
608_assign(ReactClassComponent.prototype, ReactComponent.prototype, ReactClassMixin);
609
610/**
611 * Module for creating composite components.
612 *
613 * @class ReactClass
614 */
615var ReactClass = {
616
617 /**
618 * Creates a composite component class given a class specification.
619 * See https://facebook.github.io/react/docs/top-level-api.html#react.createclass
620 *
621 * @param {object} spec Class specification (which must define `render`).
622 * @return {function} Component constructor function.
623 * @public
624 */
625 createClass: function (spec) {
626 // To keep our warnings more understandable, we'll use a little hack here to
627 // ensure that Constructor.name !== 'Constructor'. This makes sure we don't
628 // unnecessarily identify a class without displayName as 'Constructor'.
629 var Constructor = identity(function (props, context, updater) {
630 // This constructor gets overridden by mocks. The argument is used
631 // by mocks to assert on what gets mounted.
632
633 if (process.env.NODE_ENV !== 'production') {
634 process.env.NODE_ENV !== 'production' ? warning(this instanceof Constructor, 'Something is calling a React component directly. Use a factory or ' + 'JSX instead. See: https://fb.me/react-legacyfactory') : void 0;
635 }
636
637 // Wire up auto-binding
638 if (this.__reactAutoBindPairs.length) {
639 bindAutoBindMethods(this);
640 }
641
642 this.props = props;
643 this.context = context;
644 this.refs = emptyObject;
645 this.updater = updater || ReactNoopUpdateQueue;
646
647 this.state = null;
648
649 // ReactClasses doesn't have constructors. Instead, they use the
650 // getInitialState and componentWillMount methods for initialization.
651
652 var initialState = this.getInitialState ? this.getInitialState() : null;
653 if (process.env.NODE_ENV !== 'production') {
654 // We allow auto-mocks to proceed as if they're returning null.
655 if (initialState === undefined && this.getInitialState._isMockFunction) {
656 // This is probably bad practice. Consider warning here and
657 // deprecating this convenience.
658 initialState = null;
659 }
660 }
661 !(typeof initialState === 'object' && !Array.isArray(initialState)) ? process.env.NODE_ENV !== 'production' ? invariant(false, '%s.getInitialState(): must return an object or null', Constructor.displayName || 'ReactCompositeComponent') : _prodInvariant('82', Constructor.displayName || 'ReactCompositeComponent') : void 0;
662
663 this.state = initialState;
664 });
665 Constructor.prototype = new ReactClassComponent();
666 Constructor.prototype.constructor = Constructor;
667 Constructor.prototype.__reactAutoBindPairs = [];
668
669 injectedMixins.forEach(mixSpecIntoComponent.bind(null, Constructor));
670
671 mixSpecIntoComponent(Constructor, spec);
672
673 // Initialize the defaultProps property after all mixins have been merged.
674 if (Constructor.getDefaultProps) {
675 Constructor.defaultProps = Constructor.getDefaultProps();
676 }
677
678 if (process.env.NODE_ENV !== 'production') {
679 // This is a tag to indicate that the use of these method names is ok,
680 // since it's used with createClass. If it's not, then it's likely a
681 // mistake so we'll warn you to use the static property, property
682 // initializer or constructor respectively.
683 if (Constructor.getDefaultProps) {
684 Constructor.getDefaultProps.isReactClassApproved = {};
685 }
686 if (Constructor.prototype.getInitialState) {
687 Constructor.prototype.getInitialState.isReactClassApproved = {};
688 }
689 }
690
691 !Constructor.prototype.render ? process.env.NODE_ENV !== 'production' ? invariant(false, 'createClass(...): Class specification must implement a `render` method.') : _prodInvariant('83') : void 0;
692
693 if (process.env.NODE_ENV !== 'production') {
694 process.env.NODE_ENV !== 'production' ? warning(!Constructor.prototype.componentShouldUpdate, '%s has a method called ' + 'componentShouldUpdate(). Did you mean shouldComponentUpdate()? ' + 'The name is phrased as a question because the function is ' + 'expected to return a value.', spec.displayName || 'A component') : void 0;
695 process.env.NODE_ENV !== 'production' ? warning(!Constructor.prototype.componentWillRecieveProps, '%s has a method called ' + 'componentWillRecieveProps(). Did you mean componentWillReceiveProps()?', spec.displayName || 'A component') : void 0;
696 }
697
698 // Reduce time spent doing lookups by setting these on the prototype.
699 for (var methodName in ReactClassInterface) {
700 if (!Constructor.prototype[methodName]) {
701 Constructor.prototype[methodName] = null;
702 }
703 }
704
705 return Constructor;
706 },
707
708 injection: {
709 injectMixin: function (mixin) {
710 injectedMixins.push(mixin);
711 }
712 }
713
714};
715
716module.exports = ReactClass;
\No newline at end of file