使用React元素处理事件和在DOM元素上处理事件非常相似。
有一些语法差异:
- React事件使用驼峰式命名,而非小写。
- 在JSX中,你传入一个函数作为时间处理器,而非一个字符串。
举个例子,下面这个HTML:
<button onclick="activateLasers()">
Activate Lasers
</button>
在React中有些许不同:
<button onClick={activateLasers}>
Activate Lasers
</button>
另外一处不同就是在React中你不能返回false
来阻止默认行为。你必须显式地调用preventDefault
。举例来说,在简单的HTML中,如果你想阻止链接打开一个新页面的这个默认行为,可以这么写:
<a href="#" onclick="console.log('The link was clicked.'); return false">
Click me
</a>
在React中,是这样的:
function ActionLink() {
function handleClick(e) {
e.preventDefault();
console.log('The link was clicked.');
}
return (
<a href="#" onClick={handleClick}>
Click me
</a>
);
}
这里,e
是一个合成的事件。React依照W3C规则定义的这些合成事件,因此你无需担心浏览器之间的兼容性。查看SyntheticEvent
参考指南来了解更多。
在使用React时,一般来说你不需要在一个DOM元素创建后调用addEventListener
来为其添加监听器。而应该在元素初始化渲染的时候提供一个监听器。
当你使用ES6类去定义一个组件时,一个事件处理器一般作为类的方法而存在。举例来说,下面这个Toggle
组件渲染一个可以让用户在"ON"和"OFF"状态间切换的按钮:
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')
);
在CodePen上试一试
在JSX的回调函数中你必须格外小心this
的含义。在JavaScript中,类方法默认不会被绑定。如果你忘记绑定this.handleClick
,然后将他传递给onClick
,当这个函数被调用时,this
将会是undefined
。
这不只是React才有的行为;这是由于JavaScript中函数工作的方式导致的。通常情况下,如果你引用一个方法,但是后面没有加上()
,比如onClick={this.handleClick}
,那你就应该绑定那个方法。
如果调用bind
让你很烦恼,这有两个方法可以让你解决这个问题。如果你正在使用还在试验阶段的属性初始化语法,那你就可以使用属性初始化来正确的绑定回调:
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>
);
}
}
在创建React应用中,这个语法是默认开启的。
如果你没有在使用属性初始值语法,也可以在回调函数中使用箭头函数:
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>
);
}
}
这种语法的问题就是每次LogginButton
渲染的时候,都会创建一个不同的回调函数。多数情况下这都是可以接受的。但如果这个回调作为prop传递给下面的组件,下面的这些组件可能会进行额外的重新渲染。我们通常建议在构造函数中绑定或使用属性初始器语法来避免这种性能问题。