# 處理事件
使用 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 傳遞給更下層的組件,這些組件可能會有額外的重復渲染。我們通常建議在構造函數中進行綁定,以避免這類性能問題。