react 的事件处理和DOM的事件处理其实是比较像的,但是因为jsx更加偏向js,所以我们定义事件处理函数的时候应该使用驼峰命名法。
- 比如DOM中是onclick
- react里面是onClick
react不能够在处理函数中使用return false来阻止默认行为,必须在事件对象e上明确使用e.preventDefault(),而且这个事件对象e是模拟的DOM中的e对象,称为合成事件.
事件的处理函数我们可以直接定义在组件的class中,不过我们需要注意处理函数的this
指向问题,看个例子:
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(prevState => ({
isToggleOn: !prevState.isToggleOn
}));
}
render() {
return (
<button onClick={this.handleClick}>
{this.state.isToggleOn ? 'ON' : 'OFF'}
</button>
);
}
}
ReactDOM.render(
<Toggle />,
document.getElementById('root')
);
注意构造函数中的this.handleClick 绑定了this,如果我们没有这句话的话,handleClick函数中的this其实是undefined,所以我们在使用一些非官方的方法的时候(官方的方法是绑定了this的,比如componentDidMount
)一定要记得绑定this
,当然这样可能太麻烦了,我们怎么可能这么用,所以我们一般都使用实验性质的属性初始化器(这个是利用babel),可能不太懂是什么意思,我们看一个例子
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>
);
}
}
其实就是把本来需要在构造其中定义的属性放在class里面定义了,state我们也可以这么写。
如果我们不这么写,那我们就在onClick的时候外面套一层箭头函数:
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>
);
}
}
这个方法有一个问题就是每次渲染这个组件的时候,都会创建一个不同的回调函数。
所以我们使用属性初始化器来避免这类性能问题。
最后,有些情况下,我们会给事件处理函数传递额外的参数(除了合成事件e),那么我们在定义事件处理函数的时候把合成事件e作为最后一个参数。看个例子:
<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>
我们有两种方式来把事件处理函数和组件绑定,可以看到如果我们要传递额外的参数给处理函数的话,我们没法再写成原来的那个<button onClick={this.handleClick}>
因为这样没法传递额外的参数,所以我们必须写成上面这两种的一种。
这两种中bind方法是比较好的方式,因为我们不需要显示传递e,而且没有额外的匿名函数。