最近在写 React,对于将一个事件处理函数绑定到按钮上,总是有一种感觉:这么写也行,那么写也行。所以就参考了文档,整理了一下各种写法。主要是参考 React 的文档来写的,非常基础,非 React 的入门同学,这篇文章可以不看了。

绑定事件最基本的做法如下:

JavaScript

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

class Toggle extends React.Component {

  constructor(props) {

    super(props);

    this.state = {isToggleOn: true};

    // This binding is necessary to make `this` work in the callback

    this.handleClick = this.handleClick.bind(this);

  }

  handleClick() {

    this.setState(state => ({

      isToggleOn: !state.isToggleOn

    }));

  }

  render() {

    return (

      <button onClick={this.handleClick}>

        {this.state.isToggleOn ? 'ON' : 'OFF'}

      </button>

    );

  }

}

ReactDOM.render(

  <Toggle />,

  document.getElementById('root')

);

第 18 行将 this.handleClick 绑定到了按钮上。注意这里第 7 行在类的初始化函数中有一个绑定 this 的操作,这个是必须的。如果不写,那么 handleClick() 函数中的 this 将会是 undefined (这个是 JS 的特性,不是 React 的)。在 console 中会看到错误如下:

Python

1

Uncaught TypeError: Cannot read property 'setState' of undefined

如果你写过 jQuery,从这个例子中可以看出,和 jQuery 绑定事件的区别如下:

  1. 不是传入一个 string ,而是函数

  2. 组织默认的形式不是 return false 而是 e.preventDefault()

  3. jquery 是小写命名,React 是驼峰命名

  4. 不要往 DOM 上面去添加 Listener,而是在 render 的时候提供 listener

如果不想每次在初始化函数中写一个 bind,可以有两种方案:

第一种,将函数定义为 class 的一个 field:

JavaScript

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

class LoggingButton extends React.Component {

  // This syntax ensures `this` is bound within handleClick.

  // Warning: this is *experimental* syntax.

  handleClick = () => {

    console.log('this is:', this);

  }

  render() {

    return (

      <button onClick={this.handleClick}>

        Click me

      </button>

    );

  }

}

第二种,绑定的时候定义一个匿名函数(箭头函数),将匿名函数与元素绑定,而不是直接绑定事件处理函数,这样 this 在匿名函数中就不是 undefined 了:

Python

1

2

3

4

5

6

7

8

9

10

11

12

13

14

class LoggingButton extends React.Component {

  handleClick() {

    console.log('this is:', this);

  }

  render() {

    // This syntax ensures `this` is bound within handleClick

    return (

      <button onClick={(e) => this.handleClick(e)}>

        Click me

      </button>

    );

  }

}

第二种方法有一个问题,每次 LoggingButton 渲染的时候都会创建一个新的 callback 匿名函数。在这个例子中没有问题,但是如果将这个 onClick 的值作为 props 传给子组件的时候,将会导致子组件重新 render,所以不推荐。

Bind 函数的时候传递参数,下面两种写法都可以(推荐第二种):

Java

1

2

<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>

<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>

在第二种中,e 代表 React Event,将会自动作为第二个参数。