React 元素的事件處理和 DOM元素的很類似。可是有一點語法上的不一樣:javascript
例如,傳統的 HTML:html
<button onclick="activateLasers()"> Activate Lasers </button>
React 中稍稍有點不一樣:java
<button onClick={activateLasers}> Activate Lasers </button>
在 React 中另外一個不一樣是你不能使用返回 false 的方式阻止默認行爲。你必須明確的使用 preventDefault 。例如,傳統的 HTML 中阻止連接默認打開一個新頁面,你能夠這樣寫:react
<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 spec 來定義這些合成事件,因此你不須要擔憂跨瀏覽器的兼容性問題。查看 SyntheticEvent 參考指南來了解更多。babel
使用 React 的時候一般你不須要使用 addEventListener
爲一個已建立的 DOM 元素添加監聽器。你僅僅須要在這個元素初始渲染的時候提供一個監聽器。函數
當你使用 ES6 class 語法來定義一個組件的時候,事件處理器會成爲類的一個方法。例如,下面的 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') );
你必須謹慎對待 JSX 回調函數中的 this
,類的方法默認是不會綁定 this
的。若是你忘記綁定 this.handleClick
並把它傳入 onClick
, 當你調用這個函數的時候 this
的值會是 undefined
。this
這並非 React 的特殊行爲;它是函數如何在 JavaScript 中運行的一部分。一般狀況下,若是你沒有在方法後面添加 ()
,例如 onClick={this.handleClick}
,你應該爲這個方法綁定 this
.spa
若是使用 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
渲染的時候都會建立一個不一樣的回調函數。在大多數狀況下,這沒有問題。然而若是這個回調函數做爲一個屬性值傳入低階組件,這些組件可能會進行額外的從新渲染。咱們一般建議在構造函數中綁定或使用屬性初始化器語法來避免這類性能問題。
一般咱們會爲事件處理程序傳遞額外的參數。例如,如果 id
是一個內聯 id,如下兩種方式均可以向事件處理程序傳遞參數:
<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button> <button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>
上述兩種方式是等價的,分別經過 arrow functions 和 Function.prototype.bind
來爲特定事件類型添加事件處理程序。
上面兩個例子中,參數 e
做爲 React 事件對象將會被做爲第二個參數進行傳遞。經過箭頭函數的方式,事件對象必須顯式的進行傳遞,可是經過 bind
的方式,事件對象以及更多的參數將會被隱式的進行傳遞。
值得注意的是,經過 bind
方式向監聽函數傳參,在類組件中定義的監聽函數,事件對象 e
要排在所傳遞參數的後面,例如:
class Popper extends React.Component{ constructor(){ super(); this.state = {name:'Hello world!'}; } preventPop(name, e){ //事件對象e要放在最後 e.preventDefault(); alert(name); } render(){ return ( <div> <p>hello</p> {/* Pass params via bind() method. */} <a href="https://reactjs.org" onClick={this.preventPop.bind(this,this.state.name)}>Click</a> </div> ); } }