是否可以为 React 的 class 模型打开 React.js 自动绑定

Is it possible to turn on React.js autobinding for React's class model

根据 this blog postReact.createClass 中的所有方法绑定到 this 的特性在 React 的 class 中 不是内置的 ] 模特.

是否可以默认打开它?

我知道可以使用 this.someMethod = this.ticksomeMethod.bind(this); 技巧手动执行此操作,但是否可以 对所有方法都执行此操作?或者我是否被迫为所有方法编写 bind

我现在的代码示例:

import MessageStore from '../stores/MessageStore.js';

export default class Feed extends React.Component {
   constructor() {
      this.state = {messages: MessageStore.getAll()}
      //can I avoid writing this for every single method?
      this._onChange = this._onChange.bind(this); 
   }

   _onChange() {
       this.setState({messages: MessageStore.getAll()});
   };

   // componentDidMount, componentWillUnmount and render methods ommited
}

目前 React 中没有激活功能可以执行此操作。这根本不是一个选择。

您可以 post 处理 class 并自动 bind 每个函数,但这在许多 classes 中可能是不必要的,并且会增加每次调用的开销 (因为您的代码可能会混合需要绑定的函数和一些不需要的函数)。

您需要决定自动调整是否值得,或者仅在事件回调的上下文中使用 bind 语法,JavaScript 中需要它的典型位置是可以接受的。

有一个使用优雅的@decorator 语法的新解决方案。 您必须为 Babel 启用 JavaScript ES2015 stage-0 功能,但之后就变得轻而易举了! 然后你可以写:

import autobind from 'autobind-decorator'
// (...)
<li onClick={ this.closeFeedback }>Close</li>
// (...)
@autobind
closeFeedback() {
  this.setState( { closed: true } );
}

要使其正常工作,您需要安装一些构建库。方法如下:

npm install --save-dev babel-preset-stage-0
npm install --save-dev babel-plugin-react-transform
npm install --save-dev babel-plugin-transform-decorators-legacy
npm install --save-dev autobind-decorator

或者将它们全部打包在一个命令中:

npm install --save-dev babel-preset-stage-0 babel-plugin-react-transform babel-plugin-transform-decorators-legacy autobind-decorator

之后,根据您指定的 babel 设置更改 .babelrcwebpack.config.js

query: {
  presets: ['es2015', 'react', 'stage-0'],
  plugins: [['transform-decorators-legacy']]
}

(请注意,在 .babelrc 文件中,根节点从查询对象开始。)

祝你好运,不要忘记导入语句!

如果您不想或还不能使用 babel 装饰器语法。您可以定义一个自动绑定函数并在 class 中添加一行样板来处理自动绑定。

function autobind(target) { // <-- Define your autobind helper
    for (let prop of Object.getOwnPropertyNames(Object.getPrototypeOf(target))) {
        if (typeof target[prop] !== 'function') {
            continue;
        }
        if (~target[prop].toString().replace(/\s/g, '').search(`^${prop}[(][^)]*[)][{;][\'\"]autobind[\'\"];`)) {
            target[prop] = target[prop].bind(target);
        }
    }
}

class Test {
    constructor() {
        autobind(this); // <- single line of boilerplate
        this.message = 'message';
    }
    method1(){ return this.method2(); }
    method2(){ console.log(this.message);}
    _handleClick() { 'autobind'; // <-- autobind searches for functions with 'autobind' as their first expression.
        console.log(this.message);
    }
}

let test = new Test();
let _handleClick = test._handleClick;
_handleClick();