@samitouri / QOS-React-2 / commits / 02de96f012

Fix Merging `propTypes`, `contextTypes`, and `childContextTypes`

This fixes merging of `propTypes`, `contextTypes`, and `childContextTypes` so that we actually merge (instead of only taking the component or last mixin).

Tim Yung committed Dec 11, 2013 at 13:40 UTC 02de96f012cc535659eb26b79b9827d6e1f7eb7d
2 files changed +40 -9
src/core/ReactCompositeComponent.js
+10 -7
@@ -100,7 +100,7 @@ var ReactCompositeComponentInterface = {
100 * @type {object}
101 * @optional
102 */
103 - statics: SpecPolicy.DEFINE_MANY_MERGED,
103 + statics: SpecPolicy.DEFINE_MANY,
104
105 /**
106 * Definition of prop types for this component.
@@ -108,7 +108,7 @@ var ReactCompositeComponentInterface = {
108 * @type {object}
109 * @optional
110 */
111 - propTypes: SpecPolicy.DEFINE_MANY_MERGED,
111 + propTypes: SpecPolicy.DEFINE_MANY,
112
113 /**
114 * Definition of context types for this component.
@@ -116,7 +116,7 @@ var ReactCompositeComponentInterface = {
116 * @type {object}
117 * @optional
118 */
119 - contextTypes: SpecPolicy.DEFINE_MANY_MERGED,
119 + contextTypes: SpecPolicy.DEFINE_MANY,
120
121 /**
122 * Definition of context types this component sets for its children.
@@ -124,7 +124,7 @@ var ReactCompositeComponentInterface = {
124 * @type {object}
125 * @optional
126 */
127 - childContextTypes: SpecPolicy.DEFINE_MANY_MERGED,
127 + childContextTypes: SpecPolicy.DEFINE_MANY,
128
129 // ==== Definition methods ====
130
@@ -337,7 +337,10 @@ var RESERVED_SPEC_KEYS = {
337 childContextTypes,
338 ReactPropTypeLocations.childContext
339 );
340 - Constructor.childContextTypes = childContextTypes;
340 + Constructor.childContextTypes = merge(
341 + Constructor.childContextTypes,
342 + childContextTypes
343 + );
344 },
345 contextTypes: function(ConvenienceConstructor, contextTypes) {
346 var Constructor = ConvenienceConstructor.componentConstructor;
@@ -346,7 +349,7 @@ var RESERVED_SPEC_KEYS = {
349 contextTypes,
350 ReactPropTypeLocations.context
351 );
349 - Constructor.contextTypes = contextTypes;
352 + Constructor.contextTypes = merge(Constructor.contextTypes, contextTypes);
353 },
354 propTypes: function(ConvenienceConstructor, propTypes) {
355 var Constructor = ConvenienceConstructor.componentConstructor;
@@ -355,7 +358,7 @@ var RESERVED_SPEC_KEYS = {
358 propTypes,
359 ReactPropTypeLocations.prop
360 );
358 - Constructor.propTypes = propTypes;
361 + Constructor.propTypes = merge(Constructor.propTypes, propTypes);
362 },
363 statics: function(ConvenienceConstructor, statics) {
364 mixStaticSpecIntoComponent(ConvenienceConstructor, statics);
src/core/__tests__/ReactCompositeComponentMixin-test.js
+30 -2
@@ -40,6 +40,9 @@ describe('ReactCompositeComponent-mixin', function() {
40 componentPropValidator = mocks.getMockFunction();
41
42 var MixinA = {
43 + propTypes: {
44 + propA: function() {}
45 + },
46 componentDidMount: function() {
47 this.props.listener('MixinA didMount');
48 }
@@ -47,12 +50,18 @@ describe('ReactCompositeComponent-mixin', function() {
50
51 var MixinB = {
52 mixins: [MixinA],
53 + propTypes: {
54 + propB: function() {}
55 + },
56 componentDidMount: function() {
57 this.props.listener('MixinB didMount');
58 }
59 };
60
61 var MixinC = {
62 + statics: {
63 + staticC: function() {}
64 + },
65 componentDidMount: function() {
66 this.props.listener('MixinC didMount');
67 }
@@ -66,11 +75,15 @@ describe('ReactCompositeComponent-mixin', function() {
75
76 TestComponent = React.createClass({
77 mixins: [MixinB, MixinC, MixinD],
69 -
78 + statics: {
79 + staticComponent: function() {}
80 + },
81 + propTypes: {
82 + propComponent: function() {}
83 + },
84 componentDidMount: function() {
85 this.props.listener('Component didMount');
86 },
73 -
87 render: function() {
88 return <div />;
89 }
@@ -87,6 +100,21 @@ describe('ReactCompositeComponent-mixin', function() {
100 });
101 });
102
103 + it('should support merging propTypes and statics', function() {
104 + var listener = mocks.getMockFunction();
105 + var instance = <TestComponent listener={listener} />;
106 + ReactTestUtils.renderIntoDocument(instance);
107 +
108 + var instancePropTypes = instance.constructor.propTypes;
109 +
110 + expect('propA' in instancePropTypes).toBe(true);
111 + expect('propB' in instancePropTypes).toBe(true);
112 + expect('propComponent' in instancePropTypes).toBe(true);
113 +
114 + expect('staticC' in TestComponent).toBe(true);
115 + expect('staticComponent' in TestComponent).toBe(true);
116 + });
117 +
118 it('should support chaining delegate functions', function() {
119 var listener = mocks.getMockFunction();
120 var instance = <TestComponent listener={listener} />;