React版本:15.4.2
**翻译:xiyoki **
使用React元素处理事件与处理DOM元素上的事件非常相似。有一些句法差异:
React事件使用camelCase命名,而不是小写命名。
使用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
组件渲染一个按钮,让用户在‘开’和‘关’这两个状态间进行切换。
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
在JSX回调中的含义。在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>
);
}
}
这个语法在Create React App中是默认启用的。
如果你不使用属性初始化语法,你可以在回调中使用一个箭头函数:
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
渲染时,不同的回调被创建。在大多数情况下,这是可以的。然而,如果这个回调作为一个prop传递给较低的组件,这些组件可能会做额外的重新渲染。我们一般建议在构造函数中使用绑定或使用属性初始化语法,以避免这种性能问题。