# 处理事件
使用 React 元素处理事件跟在 DOM 元素上处理事件非常相似。但是有一些语法上的差别:
* React 事件使用驼峰命名法,而不是小写。
* 利用 JSX 你传递一个函数作为事件处理程序,而不是一个字符串。
例如,HTML:
~~~
<button onclick="activateLasers()">
Activate Lasers
</button>
~~~
在 React 中略有不同:
~~~
<button onClick={activateLasers}>
Activate Lasers
</button>
~~~
另一个区别是,在 React 中你不能通过 return 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 规范](https://www.w3.org/TR/DOM-Level-3-Events/) 定义了这个合成事件,所以你不需要担心浏览器的兼容性。查看 [SyntheticEvent](https://facebook.github.io/react/docs/events.html) 参考指南了解更多。
当使用 React 时,你一般不需要调用 addEventListener 来 DOM 元素被创建后为它添加监听器。相反,只要当元素被初始渲染的时候提供一个监听器就可以了。
当使用一个[ ES6 类](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Classes)定义了一个组件,通常的一个事件处理程序是类上的一个方法。例如, Toggle 组件渲染一个按钮,使用户在 “ON” 和 "OFF" 状态之间切换:
~~~
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = {isToggleOn: true};
// 这个绑定是为了使 'this' 在回调中可以正常使用
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 中[打开查看](http://codepen.io/gaearon/pen/xEmzGg?editors=0010)。
必须小心这个 JSX 回调的意义。在 JavaScript 中,类方法默认没有[绑定](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_objects/Function/bind)。如果你忘记绑定 this.handleClick 并传递它到 onClic 上,函数实际被调用时,this 将是 underfined。
这并不是 React 特有的行为;这是[函数在 JavaScript 中的工作方式](https://www.smashingmagazine.com/2014/01/understanding-javascript-function-prototype-bind/)。通常,如果你不实用 () 引用一个方法,比如 onClick={this.handleClick},你应该绑定这个方法。
如果调用绑定使你厌烦,有两种方式可以获得解脱。如果你在使用试验性质的初始化语法,可以使用属性初始化来纠正绑定回调:
~~~
class LoggingButton extends React.Component {
// 这个语法确保 `this` 被绑定在这个 handleClick 中
// 警告:这是实验性质的语法
handleClick = () => {
console.log('this is:', this);
}
render() {
return (
<button onClick={this.handleClick}>
Click me
</button>
);
}
}
~~~
这个语法在 [创建 React App](https://github.com/facebookincubator/create-react-app) 中是默认开启的。
如果你没有使用属性初始化语法,可以在回调中使用一个[箭头函数](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/Arrow_functions):
~~~
class LoggingButton extends React.Component {
handleClick() {
console.log('this is:', this);
}
render() {
// 这个语法确保 `this` 被绑定在 handleClick 中
return (
<button onClick={(e) => this.handleClick(e)}>
Click me
</button>
);
}
}
~~~
这个语法的问题是,每次 LoggingButton 渲染时都创建一个不同的回调。在多数情况下,这是没问题的。然而,如果这个回调被作为 pros 传递给更下层的组件,这些组件可能会有额外的重复渲染。我们通常建议在构造函数中进行绑定,以避免这类性能问题。