绑定与箭头功能(用于响应onClick事件)

时间:2018-05-16 16:04:08

标签: javascript reactjs

所以我正在努力学习反应,并在构造函数中理解.bind(this)。但是我想我现在明白了,只是想知道为什么我会在onClick中使用它与箭头函数。请参阅以下代码:

绑定方法可确保eventClick函数中的“this”引用类

Class Click extends react.Component {
  constructor(props) {
   super(props)
   this.clickEvent = this.clickEvent.bind(this);
  }

  render = () => (
    <button onClick={this.clickEvent}>Click Me</button>
  )

  clickEvent() {console.log(this)} // 'this' refers to the class
}

但是这个方法也引用了这个类。是否有任何赞成使用一个与另一个相比?

Class Click extends react.Component {

  render = () => (
    <button onClick={() => {this.clickEvent()}}>Click Me</button>
  )

  clickEvent() {console.log(this)} // 'this' refers to the class
}

2 个答案:

答案 0 :(得分:13)

您的第二个示例会在每个render上重新创建该函数。在您的第一个中,您只需创建一次绑定函数。

您可以在构造函数中创建处理程序作为箭头函数:

class Click extends react.Component {
  constructor(props) {
    super(props)
    this.clickEvent = () => {   // ***
      console.log(this);        // ***
    };                          // ***
  }

  render = () => (
    <button onClick={this.clickEvent}>Click Me</button>
  )
}

使用class fields proposal syntax(在大多数React项目的转换程序设置中启用,以及您用于render函数的那个​​),您可以这样写:

class Click extends react.Component {
  constructor(props) {
    super(props)
  }

  clickEvent = () => {          // ***
    console.log(this);          // ***
  };                            // ***

  render = () => (
    <button onClick={this.clickEvent}>Click Me</button>
  )
}

这是一回事。

附注:您正在为班级的每个实例创建单独的render函数。没有必要这样做,它可以在原型上。所以:

class Click extends react.Component {
  constructor(props) {
    super(props)
  }

  clickEvent = () => {
    console.log(this);
  };

  render() {
    return <button onClick={this.clickEvent}>Click Me</button>;
  }
}

答案 1 :(得分:1)

首先,让我们看一下每种技术的示例。

绑定:

import React from 'react';
class MyComponent extends React.Component {
  constructor(props) {
    super(props)
    this.clickHandler = this.clickHandler.bind(this);
  }

  clickHandler() {
    console.log( this )
  }

  render() {
    return <button onClick={this.clickHandler}>Click Me</button>
  }
}

箭头功能:

import React from 'react';
class MyComponent extends React.Component {
  constructor(props) {
    super(props)
  }

  clickHandler = () => {
    console.log( this )
  }

  render() {
    return <button onClick={this.clickHandler}>Click Me</button>
  }
}

优点和缺点:

在公共类字段上使用箭头功能更具可读性, 由于更少的代码行, 但是请记住,使用箭头功能会影响两件事:

首先是内存和性能;当您使用类字段定义函数时,整个方法都驻留在该类的每个实例上,而不是在原型上,而是使用 bind 技术, callback存储在每个实例上,它调用存储在原型上的方法。

第二个可能受影响的是您编写单元测试的方式。 您将无法使用组件原型对以下函数调用进行存根:

const spy = jest.spyOn(MyComponent.prototype, 'clickHandler');
expect(spy).toHaveBeenCalled();

您将必须找到另一种方法来存根该方法,方法是通过传递道具中的间谍检查状态更改

结论

计算机真的很擅长阅读代码;您不必为此担心。 您可能需要考虑使用类属性箭头功能使代码更易于阅读。


但是,如果要同时保持人类可读性和性能,请考虑使用plugin-transform-arrow-functions插件,只需运行npm i --save-dev @babel/plugin-transform-arrow-functions并将其添加到“ babel.config.js”或“ {{1}”中}”文件,例如:

.babelrc

您还可以使用类似auto-bind decorator的名称,将上面的示例转换为:

{
  "presets": ["module:metro-react-native-babel-preset"],
  "plugins": [
    ["@babel/plugin-proposal-decorators", { "decoratorsBeforeExport": false }],
    ["@babel/plugin-transform-arrow-functions", { "spec": true }]
  ]
}
  

注意:不必在每个函数上放置import React from 'react'; import { boundMethod as bind } from 'autobind-decorator'; class MyComponent extends React.Component { constructor(props) { super(props) } @bind clickHandler() { console.log( this ) } render() { return <button onClick={this.clickHandler}>Click Me</button> } } 。您只需要绑定传递的函数。例如@bindonClick={this.doSomething}