最近在写 React,对于将一个事件处理函数绑定到按钮上,总是有一种感觉:这么写也行,那么写也行。所以就参考了文档,整理了一下各种写法。主要是参考 React 的文档来写的,非常基础,非 React 的入门同学,这篇文章可以不看了。
绑定事件最基本的做法如下:
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 中会看到错误如下:
1 |
Uncaught TypeError: Cannot read property 'setState' of undefined |
如果你写过 jQuery,从这个例子中可以看出,和 jQuery 绑定事件的区别如下:
-
不是传入一个 string ,而是函数
-
组织默认的形式不是 return false 而是 e.preventDefault()
-
jquery 是小写命名,React 是驼峰命名
-
不要往 DOM 上面去添加 Listener,而是在 render 的时候提供 listener
如果不想每次在初始化函数中写一个 bind,可以有两种方案:
第一种,将函数定义为 class 的一个 field:
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
了:
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 函数的时候传递参数,下面两种写法都可以(推荐第二种):
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,将会自动作为第二个参数。
lol! 我的第一篇Medium写的就是这个 https://codeburst.io/react-component-event-handling-660acb1cfd07 看来绝对是个痛点啊……
主要是能做这件事的方式太多了,让人摸不清这几中有啥区别,还容易搞乱。只有一种方式多好啊。
Exactly. 最好是只有一种方法,大家都不用bibi。