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
});