@samitouri / QOS-React-2 / commits / d9fe40e147

Move Class Creation Concerns to ReactClass

This moves logic responsible for class creation and mixins into the ReactClass module. This currently creates a class that extends the ReactCompositeBase but in the future, this will be decoupled as ReactCompositeComponent will compose these classes. This is just a cut/paste.

Sebastian Markbage committed Oct 22, 2014 at 21:25 UTC d9fe40e1476d056629b9b7a28d05fd50246c0ed3
3 files changed +691 -679
src/class/ReactClass.js
+685 -1
@@ -11,6 +11,690 @@
11
12 "use strict";
13
14 -var ReactClass = require('ReactCompositeComponent');
14 +var ReactCompositeComponent = require('ReactCompositeComponent');
15 +var ReactElement = require('ReactElement');
16 +var ReactElementValidator = require('ReactElementValidator');
17 +var ReactLegacyElement = require('ReactLegacyElement');
18 +var ReactPropTypeLocations = require('ReactPropTypeLocations');
19 +var ReactPropTypeLocationNames = require('ReactPropTypeLocationNames');
20 +
21 +var assign = require('Object.assign');
22 +var invariant = require('invariant');
23 +var keyMirror = require('keyMirror');
24 +var keyOf = require('keyOf');
25 +var monitorCodeUse = require('monitorCodeUse');
26 +var mapObject = require('mapObject');
27 +
28 +var MIXINS_KEY = keyOf({mixins: null});
29 +
30 +/**
31 + * Policies that describe methods in `ReactClassInterface`.
32 + */
33 +var SpecPolicy = keyMirror({
34 + /**
35 + * These methods may be defined only once by the class specification or mixin.
36 + */
37 + DEFINE_ONCE: null,
38 + /**
39 + * These methods may be defined by both the class specification and mixins.
40 + * Subsequent definitions will be chained. These methods must return void.
41 + */
42 + DEFINE_MANY: null,
43 + /**
44 + * These methods are overriding the base class.
45 + */
46 + OVERRIDE_BASE: null,
47 + /**
48 + * These methods are similar to DEFINE_MANY, except we assume they return
49 + * objects. We try to merge the keys of the return values of all the mixed in
50 + * functions. If there is a key conflict we throw.
51 + */
52 + DEFINE_MANY_MERGED: null
53 +});
54 +
55 +
56 +var injectedMixins = [];
57 +
58 +/**
59 + * Composite components are higher-level components that compose other composite
60 + * or native components.
61 + *
62 + * To create a new type of `ReactClass`, pass a specification of
63 + * your new class to `React.createClass`. The only requirement of your class
64 + * specification is that you implement a `render` method.
65 + *
66 + * var MyComponent = React.createClass({
67 + * render: function() {
68 + * return <div>Hello World</div>;
69 + * }
70 + * });
71 + *
72 + * The class specification supports a specific protocol of methods that have
73 + * special meaning (e.g. `render`). See `ReactClassInterface` for
74 + * more the comprehensive protocol. Any other properties and methods in the
75 + * class specification will available on the prototype.
76 + *
77 + * @interface ReactClassInterface
78 + * @internal
79 + */
80 +var ReactClassInterface = {
81 +
82 + /**
83 + * An array of Mixin objects to include when defining your component.
84 + *
85 + * @type {array}
86 + * @optional
87 + */
88 + mixins: SpecPolicy.DEFINE_MANY,
89 +
90 + /**
91 + * An object containing properties and methods that should be defined on
92 + * the component's constructor instead of its prototype (static methods).
93 + *
94 + * @type {object}
95 + * @optional
96 + */
97 + statics: SpecPolicy.DEFINE_MANY,
98 +
99 + /**
100 + * Definition of prop types for this component.
101 + *
102 + * @type {object}
103 + * @optional
104 + */
105 + propTypes: SpecPolicy.DEFINE_MANY,
106 +
107 + /**
108 + * Definition of context types for this component.
109 + *
110 + * @type {object}
111 + * @optional
112 + */
113 + contextTypes: SpecPolicy.DEFINE_MANY,
114 +
115 + /**
116 + * Definition of context types this component sets for its children.
117 + *
118 + * @type {object}
119 + * @optional
120 + */
121 + childContextTypes: SpecPolicy.DEFINE_MANY,
122 +
123 + // ==== Definition methods ====
124 +
125 + /**
126 + * Invoked when the component is mounted. Values in the mapping will be set on
127 + * `this.props` if that prop is not specified (i.e. using an `in` check).
128 + *
129 + * This method is invoked before `getInitialState` and therefore cannot rely
130 + * on `this.state` or use `this.setState`.
131 + *
132 + * @return {object}
133 + * @optional
134 + */
135 + getDefaultProps: SpecPolicy.DEFINE_MANY_MERGED,
136 +
137 + /**
138 + * Invoked once before the component is mounted. The return value will be used
139 + * as the initial value of `this.state`.
140 + *
141 + * getInitialState: function() {
142 + * return {
143 + * isOn: false,
144 + * fooBaz: new BazFoo()
145 + * }
146 + * }
147 + *
148 + * @return {object}
149 + * @optional
150 + */
151 + getInitialState: SpecPolicy.DEFINE_MANY_MERGED,
152 +
153 + /**
154 + * @return {object}
155 + * @optional
156 + */
157 + getChildContext: SpecPolicy.DEFINE_MANY_MERGED,
158 +
159 + /**
160 + * Uses props from `this.props` and state from `this.state` to render the
161 + * structure of the component.
162 + *
163 + * No guarantees are made about when or how often this method is invoked, so
164 + * it must not have side effects.
165 + *
166 + * render: function() {
167 + * var name = this.props.name;
168 + * return <div>Hello, {name}!</div>;
169 + * }
170 + *
171 + * @return {ReactComponent}
172 + * @nosideeffects
173 + * @required
174 + */
175 + render: SpecPolicy.DEFINE_ONCE,
176 +
177 +
178 +
179 + // ==== Delegate methods ====
180 +
181 + /**
182 + * Invoked when the component is initially created and about to be mounted.
183 + * This may have side effects, but any external subscriptions or data created
184 + * by this method must be cleaned up in `componentWillUnmount`.
185 + *
186 + * @optional
187 + */
188 + componentWillMount: SpecPolicy.DEFINE_MANY,
189 +
190 + /**
191 + * Invoked when the component has been mounted and has a DOM representation.
192 + * However, there is no guarantee that the DOM node is in the document.
193 + *
194 + * Use this as an opportunity to operate on the DOM when the component has
195 + * been mounted (initialized and rendered) for the first time.
196 + *
197 + * @param {DOMElement} rootNode DOM element representing the component.
198 + * @optional
199 + */
200 + componentDidMount: SpecPolicy.DEFINE_MANY,
201 +
202 + /**
203 + * Invoked before the component receives new props.
204 + *
205 + * Use this as an opportunity to react to a prop transition by updating the
206 + * state using `this.setState`. Current props are accessed via `this.props`.
207 + *
208 + * componentWillReceiveProps: function(nextProps, nextContext) {
209 + * this.setState({
210 + * likesIncreasing: nextProps.likeCount > this.props.likeCount
211 + * });
212 + * }
213 + *
214 + * NOTE: There is no equivalent `componentWillReceiveState`. An incoming prop
215 + * transition may cause a state change, but the opposite is not true. If you
216 + * need it, you are probably looking for `componentWillUpdate`.
217 + *
218 + * @param {object} nextProps
219 + * @optional
220 + */
221 + componentWillReceiveProps: SpecPolicy.DEFINE_MANY,
222 +
223 + /**
224 + * Invoked while deciding if the component should be updated as a result of
225 + * receiving new props, state and/or context.
226 + *
227 + * Use this as an opportunity to `return false` when you're certain that the
228 + * transition to the new props/state/context will not require a component
229 + * update.
230 + *
231 + * shouldComponentUpdate: function(nextProps, nextState, nextContext) {
232 + * return !equal(nextProps, this.props) ||
233 + * !equal(nextState, this.state) ||
234 + * !equal(nextContext, this.context);
235 + * }
236 + *
237 + * @param {object} nextProps
238 + * @param {?object} nextState
239 + * @param {?object} nextContext
240 + * @return {boolean} True if the component should update.
241 + * @optional
242 + */
243 + shouldComponentUpdate: SpecPolicy.DEFINE_ONCE,
244 +
245 + /**
246 + * Invoked when the component is about to update due to a transition from
247 + * `this.props`, `this.state` and `this.context` to `nextProps`, `nextState`
248 + * and `nextContext`.
249 + *
250 + * Use this as an opportunity to perform preparation before an update occurs.
251 + *
252 + * NOTE: You **cannot** use `this.setState()` in this method.
253 + *
254 + * @param {object} nextProps
255 + * @param {?object} nextState
256 + * @param {?object} nextContext
257 + * @param {ReactReconcileTransaction} transaction
258 + * @optional
259 + */
260 + componentWillUpdate: SpecPolicy.DEFINE_MANY,
261 +
262 + /**
263 + * Invoked when the component's DOM representation has been updated.
264 + *
265 + * Use this as an opportunity to operate on the DOM when the component has
266 + * been updated.
267 + *
268 + * @param {object} prevProps
269 + * @param {?object} prevState
270 + * @param {?object} prevContext
271 + * @param {DOMElement} rootNode DOM element representing the component.
272 + * @optional
273 + */
274 + componentDidUpdate: SpecPolicy.DEFINE_MANY,
275 +
276 + /**
277 + * Invoked when the component is about to be removed from its parent and have
278 + * its DOM representation destroyed.
279 + *
280 + * Use this as an opportunity to deallocate any external resources.
281 + *
282 + * NOTE: There is no `componentDidUnmount` since your component will have been
283 + * destroyed by that point.
284 + *
285 + * @optional
286 + */
287 + componentWillUnmount: SpecPolicy.DEFINE_MANY,
288 +
289 +
290 +
291 + // ==== Advanced methods ====
292 +
293 + /**
294 + * Updates the component's currently mounted DOM representation.
295 + *
296 + * By default, this implements React's rendering and reconciliation algorithm.
297 + * Sophisticated clients may wish to override this.
298 + *
299 + * @param {ReactReconcileTransaction} transaction
300 + * @internal
301 + * @overridable
302 + */
303 + updateComponent: SpecPolicy.OVERRIDE_BASE
304 +
305 +};
306 +
307 +/**
308 + * Mapping from class specification keys to special processing functions.
309 + *
310 + * Although these are declared like instance properties in the specification
311 + * when defining classes using `React.createClass`, they are actually static
312 + * and are accessible on the constructor instead of the prototype. Despite
313 + * being static, they must be defined outside of the "statics" key under
314 + * which all other static methods are defined.
315 + */
316 +var RESERVED_SPEC_KEYS = {
317 + displayName: function(Constructor, displayName) {
318 + Constructor.displayName = displayName;
319 + },
320 + mixins: function(Constructor, mixins) {
321 + if (mixins) {
322 + for (var i = 0; i < mixins.length; i++) {
323 + mixSpecIntoComponent(Constructor, mixins[i]);
324 + }
325 + }
326 + },
327 + childContextTypes: function(Constructor, childContextTypes) {
328 + validateTypeDef(
329 + Constructor,
330 + childContextTypes,
331 + ReactPropTypeLocations.childContext
332 + );
333 + Constructor.childContextTypes = assign(
334 + {},
335 + Constructor.childContextTypes,
336 + childContextTypes
337 + );
338 + },
339 + contextTypes: function(Constructor, contextTypes) {
340 + validateTypeDef(
341 + Constructor,
342 + contextTypes,
343 + ReactPropTypeLocations.context
344 + );
345 + Constructor.contextTypes = assign(
346 + {},
347 + Constructor.contextTypes,
348 + contextTypes
349 + );
350 + },
351 + /**
352 + * Special case getDefaultProps which should move into statics but requires
353 + * automatic merging.
354 + */
355 + getDefaultProps: function(Constructor, getDefaultProps) {
356 + if (Constructor.getDefaultProps) {
357 + Constructor.getDefaultProps = createMergedResultFunction(
358 + Constructor.getDefaultProps,
359 + getDefaultProps
360 + );
361 + } else {
362 + Constructor.getDefaultProps = getDefaultProps;
363 + }
364 + },
365 + propTypes: function(Constructor, propTypes) {
366 + validateTypeDef(
367 + Constructor,
368 + propTypes,
369 + ReactPropTypeLocations.prop
370 + );
371 + Constructor.propTypes = assign(
372 + {},
373 + Constructor.propTypes,
374 + propTypes
375 + );
376 + },
377 + statics: function(Constructor, statics) {
378 + mixStaticSpecIntoComponent(Constructor, statics);
379 + }
380 +};
381 +
382 +function validateTypeDef(Constructor, typeDef, location) {
383 + for (var propName in typeDef) {
384 + if (typeDef.hasOwnProperty(propName)) {
385 + invariant(
386 + typeof typeDef[propName] == 'function',
387 + '%s: %s type `%s` is invalid; it must be a function, usually from ' +
388 + 'React.PropTypes.',
389 + Constructor.displayName || 'ReactClass',
390 + ReactPropTypeLocationNames[location],
391 + propName
392 + );
393 + }
394 + }
395 +}
396 +
397 +function validateMethodOverride(proto, name) {
398 + var specPolicy = ReactClassInterface.hasOwnProperty(name) ?
399 + ReactClassInterface[name] :
400 + null;
401 +
402 + // Disallow overriding of base class methods unless explicitly allowed.
403 + if (ReactCompositeComponent.Base.prototype.hasOwnProperty(name)) {
404 + invariant(
405 + specPolicy === SpecPolicy.OVERRIDE_BASE,
406 + 'ReactClassInterface: You are attempting to override ' +
407 + '`%s` from your class specification. Ensure that your method names ' +
408 + 'do not overlap with React methods.',
409 + name
410 + );
411 + }
412 +
413 + // Disallow defining methods more than once unless explicitly allowed.
414 + if (proto.hasOwnProperty(name)) {
415 + invariant(
416 + specPolicy === SpecPolicy.DEFINE_MANY ||
417 + specPolicy === SpecPolicy.DEFINE_MANY_MERGED,
418 + 'ReactClassInterface: You are attempting to define ' +
419 + '`%s` on your component more than once. This conflict may be due ' +
420 + 'to a mixin.',
421 + name
422 + );
423 + }
424 +}
425 +
426 +/**
427 + * Mixin helper which handles policy validation and reserved
428 + * specification keys when building React classses.
429 + */
430 +function mixSpecIntoComponent(Constructor, spec) {
431 + if (!spec) {
432 + return;
433 + }
434 +
435 + invariant(
436 + typeof spec !== 'function',
437 + 'ReactClass: You\'re attempting to ' +
438 + 'use a component class as a mixin. Instead, just use a regular object.'
439 + );
440 + invariant(
441 + !ReactElement.isValidElement(spec),
442 + 'ReactClass: You\'re attempting to ' +
443 + 'use a component as a mixin. Instead, just use a regular object.'
444 + );
445 +
446 + var proto = Constructor.prototype;
447 +
448 + // By handling mixins before any other properties, we ensure the same
449 + // chaining order is applied to methods with DEFINE_MANY policy, whether
450 + // mixins are listed before or after these methods in the spec.
451 + if (spec.hasOwnProperty(MIXINS_KEY)) {
452 + RESERVED_SPEC_KEYS.mixins(Constructor, spec.mixins);
453 + }
454 +
455 + for (var name in spec) {
456 + if (!spec.hasOwnProperty(name)) {
457 + continue;
458 + }
459 +
460 + if (name === MIXINS_KEY) {
461 + // We have already handled mixins in a special case above
462 + continue;
463 + }
464 +
465 + var property = spec[name];
466 + validateMethodOverride(proto, name);
467 +
468 + if (RESERVED_SPEC_KEYS.hasOwnProperty(name)) {
469 + RESERVED_SPEC_KEYS[name](Constructor, property);
470 + } else {
471 + // Setup methods on prototype:
472 + // The following member methods should not be automatically bound:
473 + // 1. Expected ReactClass methods (in the "interface").
474 + // 2. Overridden methods (that were mixed in).
475 + var isReactClassMethod =
476 + ReactClassInterface.hasOwnProperty(name);
477 + var isAlreadyDefined = proto.hasOwnProperty(name);
478 + var markedDontBind = property && property.__reactDontBind;
479 + var isFunction = typeof property === 'function';
480 + var shouldAutoBind =
481 + isFunction &&
482 + !isReactClassMethod &&
483 + !isAlreadyDefined &&
484 + !markedDontBind;
485 +
486 + if (shouldAutoBind) {
487 + if (!proto.__reactAutoBindMap) {
488 + proto.__reactAutoBindMap = {};
489 + }
490 + proto.__reactAutoBindMap[name] = property;
491 + proto[name] = property;
492 + } else {
493 + if (isAlreadyDefined) {
494 + var specPolicy = ReactClassInterface[name];
495 +
496 + // These cases should already be caught by validateMethodOverride
497 + invariant(
498 + isReactClassMethod && (
499 + specPolicy === SpecPolicy.DEFINE_MANY_MERGED ||
500 + specPolicy === SpecPolicy.DEFINE_MANY
501 + ),
502 + 'ReactClass: Unexpected spec policy %s for key %s ' +
503 + 'when mixing in component specs.',
504 + specPolicy,
505 + name
506 + );
507 +
508 + // For methods which are defined more than once, call the existing
509 + // methods before calling the new property, merging if appropriate.
510 + if (specPolicy === SpecPolicy.DEFINE_MANY_MERGED) {
511 + proto[name] = createMergedResultFunction(proto[name], property);
512 + } else if (specPolicy === SpecPolicy.DEFINE_MANY) {
513 + proto[name] = createChainedFunction(proto[name], property);
514 + }
515 + } else {
516 + proto[name] = property;
517 + if (__DEV__) {
518 + // Add verbose displayName to the function, which helps when looking
519 + // at profiling tools.
520 + if (typeof property === 'function' && spec.displayName) {
521 + proto[name].displayName = spec.displayName + '_' + name;
522 + }
523 + }
524 + }
525 + }
526 + }
527 + }
528 +}
529 +
530 +function mixStaticSpecIntoComponent(Constructor, statics) {
531 + if (!statics) {
532 + return;
533 + }
534 + for (var name in statics) {
535 + var property = statics[name];
536 + if (!statics.hasOwnProperty(name)) {
537 + continue;
538 + }
539 +
540 + var isReserved = name in RESERVED_SPEC_KEYS;
541 + invariant(
542 + !isReserved,
543 + 'ReactClass: You are attempting to define a reserved ' +
544 + 'property, `%s`, that shouldn\'t be on the "statics" key. Define it ' +
545 + 'as an instance property instead; it will still be accessible on the ' +
546 + 'constructor.',
547 + name
548 + );
549 +
550 + var isInherited = name in Constructor;
551 + invariant(
552 + !isInherited,
553 + 'ReactClass: You are attempting to define ' +
554 + '`%s` on your component more than once. This conflict may be ' +
555 + 'due to a mixin.',
556 + name
557 + );
558 + Constructor[name] = property;
559 + }
560 +}
561 +
562 +/**
563 + * Merge two objects, but throw if both contain the same key.
564 + *
565 + * @param {object} one The first object, which is mutated.
566 + * @param {object} two The second object
567 + * @return {object} one after it has been mutated to contain everything in two.
568 + */
569 +function mergeObjectsWithNoDuplicateKeys(one, two) {
570 + invariant(
571 + one && two && typeof one === 'object' && typeof two === 'object',
572 + 'mergeObjectsWithNoDuplicateKeys(): Cannot merge non-objects'
573 + );
574 +
575 + mapObject(two, function(value, key) {
576 + invariant(
577 + one[key] === undefined,
578 + 'mergeObjectsWithNoDuplicateKeys(): ' +
579 + 'Tried to merge two objects with the same key: `%s`. This conflict ' +
580 + 'may be due to a mixin; in particular, this may be caused by two ' +
581 + 'getInitialState() or getDefaultProps() methods returning objects ' +
582 + 'with clashing keys.',
583 + key
584 + );
585 + one[key] = value;
586 + });
587 + return one;
588 +}
589 +
590 +/**
591 + * Creates a function that invokes two functions and merges their return values.
592 + *
593 + * @param {function} one Function to invoke first.
594 + * @param {function} two Function to invoke second.
595 + * @return {function} Function that invokes the two argument functions.
596 + * @private
597 + */
598 +function createMergedResultFunction(one, two) {
599 + return function mergedResult() {
600 + var a = one.apply(this, arguments);
601 + var b = two.apply(this, arguments);
602 + if (a == null) {
603 + return b;
604 + } else if (b == null) {
605 + return a;
606 + }
607 + return mergeObjectsWithNoDuplicateKeys(a, b);
608 + };
609 +}
610 +
611 +/**
612 + * Creates a function that invokes two functions and ignores their return vales.
613 + *
614 + * @param {function} one Function to invoke first.
615 + * @param {function} two Function to invoke second.
616 + * @return {function} Function that invokes the two argument functions.
617 + * @private
618 + */
619 +function createChainedFunction(one, two) {
620 + return function chainedFunction() {
621 + one.apply(this, arguments);
622 + two.apply(this, arguments);
623 + };
624 +}
625 +
626 +var ReactClass = {
627 +
628 + /**
629 + * Creates a composite component class given a class specification.
630 + *
631 + * @param {object} spec Class specification (which must define `render`).
632 + * @return {function} Component constructor function.
633 + * @public
634 + */
635 + createClass: function(spec) {
636 + var Constructor = function(props) {
637 + // This constructor is overridden by mocks. The argument is used
638 + // by mocks to assert on what gets mounted. This will later be used
639 + // by the stand-alone class implementation.
640 + };
641 + Constructor.prototype = new ReactCompositeComponent.Base();
642 + Constructor.prototype.constructor = Constructor;
643 +
644 + injectedMixins.forEach(
645 + mixSpecIntoComponent.bind(null, Constructor)
646 + );
647 +
648 + mixSpecIntoComponent(Constructor, spec);
649 +
650 + // Initialize the defaultProps property after all mixins have been merged
651 + if (Constructor.getDefaultProps) {
652 + Constructor.defaultProps = Constructor.getDefaultProps();
653 + }
654 +
655 + invariant(
656 + Constructor.prototype.render,
657 + 'createClass(...): Class specification must implement a `render` method.'
658 + );
659 +
660 + if (__DEV__) {
661 + if (Constructor.prototype.componentShouldUpdate) {
662 + monitorCodeUse(
663 + 'react_component_should_update_warning',
664 + { component: spec.displayName }
665 + );
666 + console.warn(
667 + (spec.displayName || 'A component') + ' has a method called ' +
668 + 'componentShouldUpdate(). Did you mean shouldComponentUpdate()? ' +
669 + 'The name is phrased as a question because the function is ' +
670 + 'expected to return a value.'
671 + );
672 + }
673 + }
674 +
675 + // Reduce time spent doing lookups by setting these on the prototype.
676 + for (var methodName in ReactClassInterface) {
677 + if (!Constructor.prototype[methodName]) {
678 + Constructor.prototype[methodName] = null;
679 + }
680 + }
681 +
682 + if (__DEV__) {
683 + return ReactLegacyElement.wrapFactory(
684 + ReactElementValidator.createFactory(Constructor)
685 + );
686 + }
687 + return ReactLegacyElement.wrapFactory(
688 + ReactElement.createFactory(Constructor)
689 + );
690 + },
691 +
692 + injection: {
693 + injectMixin: function(mixin) {
694 + injectedMixins.push(mixin);
695 + }
696 + }
697 +
698 +};
699
700 module.exports = ReactClass;
src/core/ReactCompositeComponent.js
+1 -673
@@ -15,381 +15,22 @@ var ReactComponent = require('ReactComponent');
15 var ReactContext = require('ReactContext');
16 var ReactCurrentOwner = require('ReactCurrentOwner');
17 var ReactElement = require('ReactElement');
18 -var ReactElementValidator = require('ReactElementValidator');
18 var ReactEmptyComponent = require('ReactEmptyComponent');
19 var ReactErrorUtils = require('ReactErrorUtils');
21 -var ReactLegacyElement = require('ReactLegacyElement');
20 var ReactOwner = require('ReactOwner');
21 var ReactPerf = require('ReactPerf');
22 var ReactPropTransferer = require('ReactPropTransferer');
23 var ReactPropTypeLocations = require('ReactPropTypeLocations');
26 -var ReactPropTypeLocationNames = require('ReactPropTypeLocationNames');
24 var ReactUpdates = require('ReactUpdates');
25
26 var assign = require('Object.assign');
27 var instantiateReactComponent = require('instantiateReactComponent');
28 var invariant = require('invariant');
29 var keyMirror = require('keyMirror');
33 -var keyOf = require('keyOf');
30 var monitorCodeUse = require('monitorCodeUse');
35 -var mapObject = require('mapObject');
31 var shouldUpdateReactComponent = require('shouldUpdateReactComponent');
32 var warning = require('warning');
33
39 -var MIXINS_KEY = keyOf({mixins: null});
40 -
41 -/**
42 - * Policies that describe methods in `ReactCompositeComponentInterface`.
43 - */
44 -var SpecPolicy = keyMirror({
45 - /**
46 - * These methods may be defined only once by the class specification or mixin.
47 - */
48 - DEFINE_ONCE: null,
49 - /**
50 - * These methods may be defined by both the class specification and mixins.
51 - * Subsequent definitions will be chained. These methods must return void.
52 - */
53 - DEFINE_MANY: null,
54 - /**
55 - * These methods are overriding the base ReactCompositeComponent class.
56 - */
57 - OVERRIDE_BASE: null,
58 - /**
59 - * These methods are similar to DEFINE_MANY, except we assume they return
60 - * objects. We try to merge the keys of the return values of all the mixed in
61 - * functions. If there is a key conflict we throw.
62 - */
63 - DEFINE_MANY_MERGED: null
64 -});
65 -
66 -
67 -var injectedMixins = [];
68 -
69 -/**
70 - * Composite components are higher-level components that compose other composite
71 - * or native components.
72 - *
73 - * To create a new type of `ReactCompositeComponent`, pass a specification of
74 - * your new class to `React.createClass`. The only requirement of your class
75 - * specification is that you implement a `render` method.
76 - *
77 - * var MyComponent = React.createClass({
78 - * render: function() {
79 - * return <div>Hello World</div>;
80 - * }
81 - * });
82 - *
83 - * The class specification supports a specific protocol of methods that have
84 - * special meaning (e.g. `render`). See `ReactCompositeComponentInterface` for
85 - * more the comprehensive protocol. Any other properties and methods in the
86 - * class specification will available on the prototype.
87 - *
88 - * @interface ReactCompositeComponentInterface
89 - * @internal
90 - */
91 -var ReactCompositeComponentInterface = {
92 -
93 - /**
94 - * An array of Mixin objects to include when defining your component.
95 - *
96 - * @type {array}
97 - * @optional
98 - */
99 - mixins: SpecPolicy.DEFINE_MANY,
100 -
101 - /**
102 - * An object containing properties and methods that should be defined on
103 - * the component's constructor instead of its prototype (static methods).
104 - *
105 - * @type {object}
106 - * @optional
107 - */
108 - statics: SpecPolicy.DEFINE_MANY,
109 -
110 - /**
111 - * Definition of prop types for this component.
112 - *
113 - * @type {object}
114 - * @optional
115 - */
116 - propTypes: SpecPolicy.DEFINE_MANY,
117 -
118 - /**
119 - * Definition of context types for this component.
120 - *
121 - * @type {object}
122 - * @optional
123 - */
124 - contextTypes: SpecPolicy.DEFINE_MANY,
125 -
126 - /**
127 - * Definition of context types this component sets for its children.
128 - *
129 - * @type {object}
130 - * @optional
131 - */
132 - childContextTypes: SpecPolicy.DEFINE_MANY,
133 -
134 - // ==== Definition methods ====
135 -
136 - /**
137 - * Invoked when the component is mounted. Values in the mapping will be set on
138 - * `this.props` if that prop is not specified (i.e. using an `in` check).
139 - *
140 - * This method is invoked before `getInitialState` and therefore cannot rely
141 - * on `this.state` or use `this.setState`.
142 - *
143 - * @return {object}
144 - * @optional
145 - */
146 - getDefaultProps: SpecPolicy.DEFINE_MANY_MERGED,
147 -
148 - /**
149 - * Invoked once before the component is mounted. The return value will be used
150 - * as the initial value of `this.state`.
151 - *
152 - * getInitialState: function() {
153 - * return {
154 - * isOn: false,
155 - * fooBaz: new BazFoo()
156 - * }
157 - * }
158 - *
159 - * @return {object}
160 - * @optional
161 - */
162 - getInitialState: SpecPolicy.DEFINE_MANY_MERGED,
163 -
164 - /**
165 - * @return {object}
166 - * @optional
167 - */
168 - getChildContext: SpecPolicy.DEFINE_MANY_MERGED,
169 -
170 - /**
171 - * Uses props from `this.props` and state from `this.state` to render the
172 - * structure of the component.
173 - *
174 - * No guarantees are made about when or how often this method is invoked, so
175 - * it must not have side effects.
176 - *
177 - * render: function() {
178 - * var name = this.props.name;
179 - * return <div>Hello, {name}!</div>;
180 - * }
181 - *
182 - * @return {ReactComponent}
183 - * @nosideeffects
184 - * @required
185 - */
186 - render: SpecPolicy.DEFINE_ONCE,
187 -
188 -
189 -
190 - // ==== Delegate methods ====
191 -
192 - /**
193 - * Invoked when the component is initially created and about to be mounted.
194 - * This may have side effects, but any external subscriptions or data created
195 - * by this method must be cleaned up in `componentWillUnmount`.
196 - *
197 - * @optional
198 - */
199 - componentWillMount: SpecPolicy.DEFINE_MANY,
200 -
201 - /**
202 - * Invoked when the component has been mounted and has a DOM representation.
203 - * However, there is no guarantee that the DOM node is in the document.
204 - *
205 - * Use this as an opportunity to operate on the DOM when the component has
206 - * been mounted (initialized and rendered) for the first time.
207 - *
208 - * @param {DOMElement} rootNode DOM element representing the component.
209 - * @optional
210 - */
211 - componentDidMount: SpecPolicy.DEFINE_MANY,
212 -
213 - /**
214 - * Invoked before the component receives new props.
215 - *
216 - * Use this as an opportunity to react to a prop transition by updating the
217 - * state using `this.setState`. Current props are accessed via `this.props`.
218 - *
219 - * componentWillReceiveProps: function(nextProps, nextContext) {
220 - * this.setState({
221 - * likesIncreasing: nextProps.likeCount > this.props.likeCount
222 - * });
223 - * }
224 - *
225 - * NOTE: There is no equivalent `componentWillReceiveState`. An incoming prop
226 - * transition may cause a state change, but the opposite is not true. If you
227 - * need it, you are probably looking for `componentWillUpdate`.
228 - *
229 - * @param {object} nextProps
230 - * @optional
231 - */
232 - componentWillReceiveProps: SpecPolicy.DEFINE_MANY,
233 -
234 - /**
235 - * Invoked while deciding if the component should be updated as a result of
236 - * receiving new props, state and/or context.
237 - *
238 - * Use this as an opportunity to `return false` when you're certain that the
239 - * transition to the new props/state/context will not require a component
240 - * update.
241 - *
242 - * shouldComponentUpdate: function(nextProps, nextState, nextContext) {
243 - * return !equal(nextProps, this.props) ||
244 - * !equal(nextState, this.state) ||
245 - * !equal(nextContext, this.context);
246 - * }
247 - *
248 - * @param {object} nextProps
249 - * @param {?object} nextState
250 - * @param {?object} nextContext
251 - * @return {boolean} True if the component should update.
252 - * @optional
253 - */
254 - shouldComponentUpdate: SpecPolicy.DEFINE_ONCE,
255 -
256 - /**
257 - * Invoked when the component is about to update due to a transition from
258 - * `this.props`, `this.state` and `this.context` to `nextProps`, `nextState`
259 - * and `nextContext`.
260 - *
261 - * Use this as an opportunity to perform preparation before an update occurs.
262 - *
263 - * NOTE: You **cannot** use `this.setState()` in this method.
264 - *
265 - * @param {object} nextProps
266 - * @param {?object} nextState
267 - * @param {?object} nextContext
268 - * @param {ReactReconcileTransaction} transaction
269 - * @optional
270 - */
271 - componentWillUpdate: SpecPolicy.DEFINE_MANY,
272 -
273 - /**
274 - * Invoked when the component's DOM representation has been updated.
275 - *
276 - * Use this as an opportunity to operate on the DOM when the component has
277 - * been updated.
278 - *
279 - * @param {object} prevProps
280 - * @param {?object} prevState
281 - * @param {?object} prevContext
282 - * @param {DOMElement} rootNode DOM element representing the component.
283 - * @optional
284 - */
285 - componentDidUpdate: SpecPolicy.DEFINE_MANY,
286 -
287 - /**
288 - * Invoked when the component is about to be removed from its parent and have
289 - * its DOM representation destroyed.
290 - *
291 - * Use this as an opportunity to deallocate any external resources.
292 - *
293 - * NOTE: There is no `componentDidUnmount` since your component will have been
294 - * destroyed by that point.
295 - *
296 - * @optional
297 - */
298 - componentWillUnmount: SpecPolicy.DEFINE_MANY,
299 -
300 -
301 -
302 - // ==== Advanced methods ====
303 -
304 - /**
305 - * Updates the component's currently mounted DOM representation.
306 - *
307 - * By default, this implements React's rendering and reconciliation algorithm.
308 - * Sophisticated clients may wish to override this.
309 - *
310 - * @param {ReactReconcileTransaction} transaction
311 - * @internal
312 - * @overridable
313 - */
314 - updateComponent: SpecPolicy.OVERRIDE_BASE
315 -
316 -};
317 -
318 -/**
319 - * Mapping from class specification keys to special processing functions.
320 - *
321 - * Although these are declared like instance properties in the specification
322 - * when defining classes using `React.createClass`, they are actually static
323 - * and are accessible on the constructor instead of the prototype. Despite
324 - * being static, they must be defined outside of the "statics" key under
325 - * which all other static methods are defined.
326 - */
327 -var RESERVED_SPEC_KEYS = {
328 - displayName: function(Constructor, displayName) {
329 - Constructor.displayName = displayName;
330 - },
331 - mixins: function(Constructor, mixins) {
332 - if (mixins) {
333 - for (var i = 0; i < mixins.length; i++) {
334 - mixSpecIntoComponent(Constructor, mixins[i]);
335 - }
336 - }
337 - },
338 - childContextTypes: function(Constructor, childContextTypes) {
339 - validateTypeDef(
340 - Constructor,
341 - childContextTypes,
342 - ReactPropTypeLocations.childContext
343 - );
344 - Constructor.childContextTypes = assign(
345 - {},
346 - Constructor.childContextTypes,
347 - childContextTypes
348 - );
349 - },
350 - contextTypes: function(Constructor, contextTypes) {
351 - validateTypeDef(
352 - Constructor,
353 - contextTypes,
354 - ReactPropTypeLocations.context
355 - );
356 - Constructor.contextTypes = assign(
357 - {},
358 - Constructor.contextTypes,
359 - contextTypes
360 - );
361 - },
362 - /**
363 - * Special case getDefaultProps which should move into statics but requires
364 - * automatic merging.
365 - */
366 - getDefaultProps: function(Constructor, getDefaultProps) {
367 - if (Constructor.getDefaultProps) {
368 - Constructor.getDefaultProps = createMergedResultFunction(
369 - Constructor.getDefaultProps,
370 - getDefaultProps
371 - );
372 - } else {
373 - Constructor.getDefaultProps = getDefaultProps;
374 - }
375 - },
376 - propTypes: function(Constructor, propTypes) {
377 - validateTypeDef(
378 - Constructor,
379 - propTypes,
380 - ReactPropTypeLocations.prop
381 - );
382 - Constructor.propTypes = assign(
383 - {},
384 - Constructor.propTypes,
385 - propTypes
386 - );
387 - },
388 - statics: function(Constructor, statics) {
389 - mixStaticSpecIntoComponent(Constructor, statics);
390 - }
391 -};
392 -
34 function getDeclarationErrorAddendum(component) {
35 var owner = component._owner || null;
36 if (owner && owner.constructor && owner.constructor.displayName) {
@@ -399,50 +40,6 @@ function getDeclarationErrorAddendum(component) {
40 return '';
41 }
42
402 -function validateTypeDef(Constructor, typeDef, location) {
403 - for (var propName in typeDef) {
404 - if (typeDef.hasOwnProperty(propName)) {
405 - invariant(
406 - typeof typeDef[propName] == 'function',
407 - '%s: %s type `%s` is invalid; it must be a function, usually from ' +
408 - 'React.PropTypes.',
409 - Constructor.displayName || 'ReactCompositeComponent',
410 - ReactPropTypeLocationNames[location],
411 - propName
412 - );
413 - }
414 - }
415 -}
416 -
417 -function validateMethodOverride(proto, name) {
418 - var specPolicy = ReactCompositeComponentInterface.hasOwnProperty(name) ?
419 - ReactCompositeComponentInterface[name] :
420 - null;
421 -
422 - // Disallow overriding of base class methods unless explicitly allowed.
423 - if (ReactCompositeComponentMixin.hasOwnProperty(name)) {
424 - invariant(
425 - specPolicy === SpecPolicy.OVERRIDE_BASE,
426 - 'ReactCompositeComponentInterface: You are attempting to override ' +
427 - '`%s` from your class specification. Ensure that your method names ' +
428 - 'do not overlap with React methods.',
429 - name
430 - );
431 - }
432 -
433 - // Disallow defining methods more than once unless explicitly allowed.
434 - if (proto.hasOwnProperty(name)) {
435 - invariant(
436 - specPolicy === SpecPolicy.DEFINE_MANY ||
437 - specPolicy === SpecPolicy.DEFINE_MANY_MERGED,
438 - 'ReactCompositeComponentInterface: You are attempting to define ' +
439 - '`%s` on your component more than once. This conflict may be due ' +
440 - 'to a mixin.',
441 - name
442 - );
443 - }
444 -}
445 -
43 function validateLifeCycleOnReplaceState(instance) {
44 var compositeLifeCycleState = instance._compositeLifeCycleState;
45 invariant(
@@ -462,206 +59,6 @@ function validateLifeCycleOnReplaceState(instance) {
59 );
60 }
61
465 -/**
466 - * Mixin helper which handles policy validation and reserved
467 - * specification keys when building `ReactCompositeComponent` classses.
468 - */
469 -function mixSpecIntoComponent(Constructor, spec) {
470 - if (!spec) {
471 - return;
472 - }
473 -
474 - invariant(
475 - !ReactLegacyElement.isValidFactory(spec),
476 - 'ReactCompositeComponent: You\'re attempting to ' +
477 - 'use a component class as a mixin. Instead, just use a regular object.'
478 - );
479 - invariant(
480 - !ReactElement.isValidElement(spec),
481 - 'ReactCompositeComponent: You\'re attempting to ' +
482 - 'use a component as a mixin. Instead, just use a regular object.'
483 - );
484 -
485 - var proto = Constructor.prototype;
486 -
487 - // By handling mixins before any other properties, we ensure the same
488 - // chaining order is applied to methods with DEFINE_MANY policy, whether
489 - // mixins are listed before or after these methods in the spec.
490 - if (spec.hasOwnProperty(MIXINS_KEY)) {
491 - RESERVED_SPEC_KEYS.mixins(Constructor, spec.mixins);
492 - }
493 -
494 - for (var name in spec) {
495 - if (!spec.hasOwnProperty(name)) {
496 - continue;
497 - }
498 -
499 - if (name === MIXINS_KEY) {
500 - // We have already handled mixins in a special case above
501 - continue;
502 - }
503 -
504 - var property = spec[name];
505 - validateMethodOverride(proto, name);
506 -
507 - if (RESERVED_SPEC_KEYS.hasOwnProperty(name)) {
508 - RESERVED_SPEC_KEYS[name](Constructor, property);
509 - } else {
510 - // Setup methods on prototype:
511 - // The following member methods should not be automatically bound:
512 - // 1. Expected ReactCompositeComponent methods (in the "interface").
513 - // 2. Overridden methods (that were mixed in).
514 - var isCompositeComponentMethod =
515 - ReactCompositeComponentInterface.hasOwnProperty(name);
516 - var isAlreadyDefined = proto.hasOwnProperty(name);
517 - var markedDontBind = property && property.__reactDontBind;
518 - var isFunction = typeof property === 'function';
519 - var shouldAutoBind =
520 - isFunction &&
521 - !isCompositeComponentMethod &&
522 - !isAlreadyDefined &&
523 - !markedDontBind;
524 -
525 - if (shouldAutoBind) {
526 - if (!proto.__reactAutoBindMap) {
527 - proto.__reactAutoBindMap = {};
528 - }
529 - proto.__reactAutoBindMap[name] = property;
530 - proto[name] = property;
531 - } else {
532 - if (isAlreadyDefined) {
533 - var specPolicy = ReactCompositeComponentInterface[name];
534 -
535 - // These cases should already be caught by validateMethodOverride
536 - invariant(
537 - isCompositeComponentMethod && (
538 - specPolicy === SpecPolicy.DEFINE_MANY_MERGED ||
539 - specPolicy === SpecPolicy.DEFINE_MANY
540 - ),
541 - 'ReactCompositeComponent: Unexpected spec policy %s for key %s ' +
542 - 'when mixing in component specs.',
543 - specPolicy,
544 - name
545 - );
546 -
547 - // For methods which are defined more than once, call the existing
548 - // methods before calling the new property, merging if appropriate.
549 - if (specPolicy === SpecPolicy.DEFINE_MANY_MERGED) {
550 - proto[name] = createMergedResultFunction(proto[name], property);
551 - } else if (specPolicy === SpecPolicy.DEFINE_MANY) {
552 - proto[name] = createChainedFunction(proto[name], property);
553 - }
554 - } else {
555 - proto[name] = property;
556 - if (__DEV__) {
557 - // Add verbose displayName to the function, which helps when looking
558 - // at profiling tools.
559 - if (typeof property === 'function' && spec.displayName) {
560 - proto[name].displayName = spec.displayName + '_' + name;
561 - }
562 - }
563 - }
564 - }
565 - }
566 - }
567 -}
568 -
569 -function mixStaticSpecIntoComponent(Constructor, statics) {
570 - if (!statics) {
571 - return;
572 - }
573 - for (var name in statics) {
574 - var property = statics[name];
575 - if (!statics.hasOwnProperty(name)) {
576 - continue;
577 - }
578 -
579 - var isReserved = name in RESERVED_SPEC_KEYS;
580 - invariant(
581 - !isReserved,
582 - 'ReactCompositeComponent: You are attempting to define a reserved ' +
583 - 'property, `%s`, that shouldn\'t be on the "statics" key. Define it ' +
584 - 'as an instance property instead; it will still be accessible on the ' +
585 - 'constructor.',
586 - name
587 - );
588 -
589 - var isInherited = name in Constructor;
590 - invariant(
591 - !isInherited,
592 - 'ReactCompositeComponent: You are attempting to define ' +
593 - '`%s` on your component more than once. This conflict may be ' +
594 - 'due to a mixin.',
595 - name
596 - );
597 - Constructor[name] = property;
598 - }
599 -}
600 -
601 -/**
602 - * Merge two objects, but throw if both contain the same key.
603 - *
604 - * @param {object} one The first object, which is mutated.
605 - * @param {object} two The second object
606 - * @return {object} one after it has been mutated to contain everything in two.
607 - */
608 -function mergeObjectsWithNoDuplicateKeys(one, two) {
609 - invariant(
610 - one && two && typeof one === 'object' && typeof two === 'object',
611 - 'mergeObjectsWithNoDuplicateKeys(): Cannot merge non-objects'
612 - );
613 -
614 - mapObject(two, function(value, key) {
615 - invariant(
616 - one[key] === undefined,
617 - 'mergeObjectsWithNoDuplicateKeys(): ' +
618 - 'Tried to merge two objects with the same key: `%s`. This conflict ' +
619 - 'may be due to a mixin; in particular, this may be caused by two ' +
620 - 'getInitialState() or getDefaultProps() methods returning objects ' +
621 - 'with clashing keys.',
622 - key
623 - );
624 - one[key] = value;
625 - });
626 - return one;
627 -}
628 -
629 -/**
630 - * Creates a function that invokes two functions and merges their return values.
631 - *
632 - * @param {function} one Function to invoke first.
633 - * @param {function} two Function to invoke second.
634 - * @return {function} Function that invokes the two argument functions.
635 - * @private
636 - */
637 -function createMergedResultFunction(one, two) {
638 - return function mergedResult() {
639 - var a = one.apply(this, arguments);
640 - var b = two.apply(this, arguments);
641 - if (a == null) {
642 - return b;
643 - } else if (b == null) {
644 - return a;
645 - }
646 - return mergeObjectsWithNoDuplicateKeys(a, b);
647 - };
648 -}
649 -
650 -/**
651 - * Creates a function that invokes two functions and ignores their return vales.
652 - *
653 - * @param {function} one Function to invoke first.
654 - * @param {function} two Function to invoke second.
655 - * @return {function} Function that invokes the two argument functions.
656 - * @private
657 - */
658 -function createChainedFunction(one, two) {
659 - return function chainedFunction() {
660 - one.apply(this, arguments);
661 - two.apply(this, arguments);
662 - };
663 -}
664 -
62 /**
63 * `ReactCompositeComponent` maintains an auxiliary life cycle state in
64 * `this._compositeLifeCycleState` (which can be null).
@@ -1380,77 +777,8 @@ var ReactCompositeComponent = {
777
778 LifeCycle: CompositeLifeCycle,
779
1383 - Base: ReactCompositeComponentBase,
1384 -
1385 - /**
1386 - * Creates a composite component class given a class specification.
1387 - *
1388 - * @param {object} spec Class specification (which must define `render`).
1389 - * @return {function} Component constructor function.
1390 - * @public
1391 - */
1392 - createClass: function(spec) {
1393 - var Constructor = function(props) {
1394 - // This constructor is overridden by mocks. The argument is used
1395 - // by mocks to assert on what gets mounted. This will later be used
1396 - // by the stand-alone class implementation.
1397 - };
1398 - Constructor.prototype = new ReactCompositeComponentBase();
1399 - Constructor.prototype.constructor = Constructor;
1400 -
1401 - injectedMixins.forEach(
1402 - mixSpecIntoComponent.bind(null, Constructor)
1403 - );
1404 -
1405 - mixSpecIntoComponent(Constructor, spec);
1406 -
1407 - // Initialize the defaultProps property after all mixins have been merged
1408 - if (Constructor.getDefaultProps) {
1409 - Constructor.defaultProps = Constructor.getDefaultProps();
1410 - }
1411 -
1412 - invariant(
1413 - Constructor.prototype.render,
1414 - 'createClass(...): Class specification must implement a `render` method.'
1415 - );
780 + Base: ReactCompositeComponentBase
781
1417 - if (__DEV__) {
1418 - if (Constructor.prototype.componentShouldUpdate) {
1419 - monitorCodeUse(
1420 - 'react_component_should_update_warning',
1421 - { component: spec.displayName }
1422 - );
1423 - console.warn(
1424 - (spec.displayName || 'A component') + ' has a method called ' +
1425 - 'componentShouldUpdate(). Did you mean shouldComponentUpdate()? ' +
1426 - 'The name is phrased as a question because the function is ' +
1427 - 'expected to return a value.'
1428 - );
1429 - }
1430 - }
1431 -
1432 - // Reduce time spent doing lookups by setting these on the prototype.
1433 - for (var methodName in ReactCompositeComponentInterface) {
1434 - if (!Constructor.prototype[methodName]) {
1435 - Constructor.prototype[methodName] = null;
1436 - }
1437 - }
1438 -
1439 - if (__DEV__) {
1440 - return ReactLegacyElement.wrapFactory(
1441 - ReactElementValidator.createFactory(Constructor)
1442 - );
1443 - }
1444 - return ReactLegacyElement.wrapFactory(
1445 - ReactElement.createFactory(Constructor)
1446 - );
1447 - },
1448 -
1449 - injection: {
1450 - injectMixin: function(mixin) {
1451 - injectedMixins.push(mixin);
1452 - }
1453 - }
782 };
783
784 module.exports = ReactCompositeComponent;
src/core/__tests__/ReactCompositeComponent-test.js
+5 -5
@@ -1302,7 +1302,7 @@ describe('ReactCompositeComponent', function() {
1302 }
1303 });
1304 }).toThrow(
1305 - 'Invariant Violation: ReactCompositeComponent: You are attempting to ' +
1305 + 'Invariant Violation: ReactClass: You are attempting to ' +
1306 'define a reserved property, `getDefaultProps`, that shouldn\'t be on ' +
1307 'the "statics" key. Define it as an instance property instead; it ' +
1308 'will still be accessible on the constructor.'
@@ -1353,7 +1353,7 @@ describe('ReactCompositeComponent', function() {
1353 }
1354 });
1355 }).toThrow(
1356 - 'Invariant Violation: ReactCompositeComponent: You are attempting to ' +
1356 + 'Invariant Violation: ReactClass: You are attempting to ' +
1357 'define `abc` on your component more than once. This conflict may be ' +
1358 'due to a mixin.'
1359 );
@@ -1378,7 +1378,7 @@ describe('ReactCompositeComponent', function() {
1378 }
1379 });
1380 }).toThrow(
1381 - 'Invariant Violation: ReactCompositeComponent: You are attempting to ' +
1381 + 'Invariant Violation: ReactClass: You are attempting to ' +
1382 'define `abc` on your component more than once. This conflict may be ' +
1383 'due to a mixin.'
1384 );
@@ -1394,7 +1394,7 @@ describe('ReactCompositeComponent', function() {
1394 }
1395 });
1396 }).toThrow(
1397 - 'Invariant Violation: ReactCompositeComponent: You\'re attempting to ' +
1397 + 'Invariant Violation: ReactClass: You\'re attempting to ' +
1398 'use a component as a mixin. Instead, just use a regular object.'
1399 );
1400 });
@@ -1415,7 +1415,7 @@ describe('ReactCompositeComponent', function() {
1415 }
1416 });
1417 }).toThrow(
1418 - 'Invariant Violation: ReactCompositeComponent: You\'re attempting to ' +
1418 + 'Invariant Violation: ReactClass: You\'re attempting to ' +
1419 'use a component class as a mixin. Instead, just use a regular object.'
1420 );
1421 });