The library for web and native user interfaces.
Fix a bunch of problems with implicit autobinding
CommitSyncScript committed
Jun 24, 2013 at 16:09 UTC
a61f4df0b9b23250a5a59285aad82cf7d82a19b8
2 files changed
+23
-27
src/core/ReactCompositeComponent.js
+23
-18
@@ -28,16 +28,18 @@ var keyMirror = require('keyMirror');
28
var merge = require('merge');
29
var mixInto = require('mixInto');
30
31
-var invokedBeforeMount = function() {
32
- invariant(
33
- false,
34
- 'You have invoked a method that is automatically bound, before the ' +
35
- 'instance has been mounted. There is nothing conceptually wrong with ' +
36
- 'this, but since this method will be replaced with a new version once ' +
37
- 'the component is mounted - you should be aware of the fact that this ' +
38
- 'method will soon be replaced.'
39
- );
40
-};
31
+function invokeWithWarning(func) {
32
+ return function() {
33
+ console && console.warn && console.warn(
34
+ 'You have invoked a method that is automatically bound, before the ' +
35
+ 'instance has been mounted. There is nothing conceptually wrong with ' +
36
+ 'this, but since this method will be replaced with a new version once' +
37
+ ' the component is mounted - you should be aware of the fact that ' +
38
+ 'this method will soon be replaced.'
39
+ );
40
+ return func.apply(this, arguments);
41
+ };
42
+}
43
44
/**
45
* Policies that describe methods in `ReactCompositeComponentInterface`.
@@ -370,7 +372,10 @@ function mixSpecIntoComponent(Constructor, spec) {
372
proto.__reactAutoBindMap = {};
373
}
374
proto.__reactAutoBindMap[name] = property;
373
- proto[name] = invokedBeforeMount;
375
+ proto[name] = property;
376
+ if (__DEV__) {
377
+ proto[name] = invokeWithWarning(property);
378
+ }
379
} else {
380
if (isInherited) {
381
// For methods which are defined more than once, call the existing
@@ -393,13 +398,13 @@ function mixSpecIntoComponent(Constructor, spec) {
398
* @private
399
*/
400
function createChainedFunction(one, two) {
396
- return function chainedFunction(a, b, c, d, e, tooMany) {
401
+ return function chainedFunction(a, b, c, d, e, f, g, tooMany) {
402
invariant(
403
typeof tooMany === 'undefined',
399
- 'Chained function can only take a maximum of 5 arguments.'
404
+ 'Chained function can only take a maximum of 7 arguments.'
405
);
401
- one.call(this, a, b, c, d, e);
402
- two.call(this, a, b, c, d, e);
406
+ one.call(this, a, b, c, d, e, f, g);
407
+ two.call(this, a, b, c, d, e, f, g);
408
};
409
}
410
@@ -814,12 +819,12 @@ var ReactCompositeComponentMixin = {
819
*/
820
_bindAutoBindMethod: function(method) {
821
var component = this;
817
- function autoBound(a, b, c, d, e, tooMany) {
822
+ function autoBound(a, b, c, d, e, f, g, tooMany) {
823
invariant(
824
typeof tooMany === 'undefined',
820
- 'React.autoBind(...): Methods can only take a maximum of 5 arguments.'
825
+ 'React.autoBind(...): Methods can only take a maximum of 7 arguments.'
826
);
822
- return method.call(component, a, b, c, d, e);
827
+ return method.call(component, a, b, c, d, e, f, g);
828
}
829
return autoBound;
830
}
src/core/__tests__/ReactCompositeComponent-test.js
-9
@@ -188,15 +188,6 @@ describe('ReactCompositeComponent', function() {
188
});
189
var instance = <ComponentClass />;
190
191
- // Autobound methods will throw before mounting.
192
- // TODO: We should actually allow component instance methods to be invoked
193
- // before mounting for read-only operations. We would then update this test.
194
- expect(function() {
195
- instance.methodToBeExplicitlyBound.bind(instance)();
196
- }).toThrow();
197
- expect(function() {
198
- instance.methodAutoBound();
199
- }).toThrow();
191
expect(function() {
192
instance.methodExplicitlyNotBound();
193
}).not.toThrow();