top
Loading...
React 事件處理

React 事件處理

React 元素的事件處理和 DOM 元素類似。但是有一點語法上的不同:

  • React 事件綁定屬性的命名采用駝峰式寫法,而不是小寫。
  • 如果采用 JSX 的語法你需要傳入一個函數作為事件處理函數,而不是一個字符串(DOM 元素的寫法)

HTML 通常寫法是:

<button onclick="activateLasers()">
  激活按鈕
</button>

React 中寫法為:

<button onClick={activateLasers}>
  激活按鈕
</button>

在 React 中另一個不同是你不能使用返回 false 的方式阻止默認行為, 你必須明確的使用 preventDefault

例如,通常我們在 HTML 中阻止鏈接默認打開一個新頁面,可以這樣寫:
<a href="#" onclick="console.log('點擊鏈接'); return false">
  點我
</a>

在 React 的寫法為:

function ActionLink() { function handleClick(e) { e.preventDefault(); console.log('鏈接被點擊'); } return ( <a href="#" onClick={handleClick}> 點我 </a> ); }

實例中 e 是一個合成事件。

使用 React 的時候通常你不需要使用 addEventListener 為一個已創建的 DOM 元素添加監聽器。你僅僅需要在這個元素初始渲染的時候提供一個監聽器。

當你使用 ES6 class 語法來定義一個組件的時候,事件處理器會成為類的一個方法。例如,下面的 Toggle 組件渲染一個讓用戶切換開關狀態的按鈕:

實例

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('example') );

嘗試一下 »

你必須謹慎對待 JSX 回調函數中的 this,類的方法默認是不會綁定 this 的。如果你忘記綁定 this.handleClick 併把它傳入 onClick, 當你調用這個函數的時候 this 的值會是 undefined。

這併不是 React 的特殊行為;它是函數如何在 JavaScript 中運行的一部分。通常情況下,如果你沒有在方法後面添加 () ,例如 onClick={this.handleClick},你應該為這個方法綁定 this。

如果使用 bind 讓你很煩,這里有兩種方式可以解決。如果你正在使用實驗性的屬性初始化器語法,你可以使用屬性初始化器來正確的綁定回調函數:

class LoggingButton extends React.Component { // 這個語法確保了 `this` 綁定在 handleClick 中 // 這里只是一個測試 handleClick = () => { console.log('this is:', this); } render() { return ( <button onClick={this.handleClick}> Click me </button> ); } }

如果你沒有使用屬性初始化器語法,你可以在回調函數中使用 箭頭函數:

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 渲染的時候都會創建一個不同的回調函數。在大多數情況下,這沒有問題。然而如果這個回調函數作為一個屬性值傳入低階組件,這些組件可能會進行額外的重新渲染。我們通常建議在構造函數中綁定或使用屬性初始化器語法來避免這類性能問題。


向事件處理程序傳遞參數

通常我們會為事件處理程序傳遞額外的參數。例如,若是 id 是你要刪除那一行的 id,以下兩種方式都可以向事件處理程序傳遞參數:

<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>
上述兩種方式是等價的。

上面兩個例子中,參數 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> {/* 通過 bind() 方法傳遞參數。 */} <a href="https://reactjs.org" onClick={this.preventPop.bind(this,this.state.name)}>Click</a> </div> ); } }
北斗有巢氏 有巢氏北斗