From d1bf76a3237523391d2a0dfca3d95469e62e7e5b Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Fri, 12 Dec 2014 17:26:09 +0100 Subject: [PATCH] Don't autobind methods twice and remove deprecated call --- modules/bindAutoBindMethods.js | 62 ++++++++++++++++++++++++++++++++++ modules/deepForceUpdate.js | 7 ++-- 2 files changed, 65 insertions(+), 4 deletions(-) create mode 100644 modules/bindAutoBindMethods.js diff --git a/modules/bindAutoBindMethods.js b/modules/bindAutoBindMethods.js new file mode 100644 index 0000000..5b697e0 --- /dev/null +++ b/modules/bindAutoBindMethods.js @@ -0,0 +1,62 @@ +'use strict'; + +/** + * Based on https://github.com/facebook/react/blob/master/src/class/ReactClass.js#L637 + */ +function bindAutoBindMethod(component, method) { + var boundMethod = method.bind(component); + + boundMethod.__reactBoundContext = component; + boundMethod.__reactBoundMethod = method; + boundMethod.__reactBoundArguments = null; + + var componentName = component.constructor.displayName, + _bind = boundMethod.bind; + + boundMethod.bind = function (newThis) { + var args = Array.prototype.slice.call(arguments, 1); + if (newThis !== component && newThis !== null) { + console.warn( + 'bind(): React component methods may only be bound to the ' + + 'component instance. See ' + componentName + ); + } else if (!args.length) { + console.warn( + 'bind(): You are binding a component method to the component. ' + + 'React does this for you automatically in a high-performance ' + + 'way, so you can safely remove this call. See ' + componentName + ); + return boundMethod; + } + + var reboundMethod = _bind.apply(boundMethod, arguments); + reboundMethod.__reactBoundContext = component; + reboundMethod.__reactBoundMethod = method; + reboundMethod.__reactBoundArguments = args; + + return reboundMethod; + }; + + return boundMethod; +} + +/** + * Performs auto-binding similar to how React does it. + * Skips already auto-bound methods. + * Based on https://github.com/facebook/react/blob/master/src/class/ReactClass.js#L679. + */ +module.exports = function bindAutoBindMethods(component) { + for (var autoBindKey in component.__reactAutoBindMap) { + if (!component.__reactAutoBindMap.hasOwnProperty(autoBindKey)) { + continue; + } + + if (component.hasOwnProperty(autoBindKey) && + component[autoBindKey].__reactBoundContext === component) { + continue; + } + + var method = component.__reactAutoBindMap[autoBindKey]; + component[autoBindKey] = bindAutoBindMethod(component, method); + } +}; \ No newline at end of file diff --git a/modules/deepForceUpdate.js b/modules/deepForceUpdate.js index eef67ac..ab3710a 100644 --- a/modules/deepForceUpdate.js +++ b/modules/deepForceUpdate.js @@ -1,15 +1,14 @@ 'use strict'; +var bindAutoBindMethods = require('./bindAutoBindMethods'); + /** * Updates a React component recursively, so even if children define funky * `shouldComponentUpdate`, they are forced to re-render. * Makes sure that any newly added methods are properly auto-bound. */ function deepForceUpdate(component) { - // ES6 classes won't have this - if (component._bindAutoBindMethods) { - component._bindAutoBindMethods(); - } + bindAutoBindMethods(component); if (component.forceUpdate) { component.forceUpdate();