React 事件綁定有好幾種方式,我快懵了

事件處理程序(Event handlers)就是每當有事件被觸發時決定要執行的動做或行爲。javascript

在 React 應用中,事件名使用小駝峯格式書寫,意思就是 onclick 要寫成 onClickhtml

React 實現的合成事件機制給 React 應用和接口帶來了一致性,同時具有高性能的優勢。它經過將事件標準化來達到一致性,從而達到在不一樣瀏覽器和平臺上都具備相同的屬性。java

合成事件是瀏覽器的原生事件的跨瀏覽器包裝器。除兼容全部瀏覽器外,它還擁有和瀏覽器原生事件相同的接口,包括 stopPropagation()preventDefault()react

合成事件的高性能是經過自動使用事件代理實現的。事實上,React 並不將事件處理程序綁定到節點自身,而是將一個事件監聽器綁定到 document 的根元素上。每當有事件被觸發,React 就將事件監聽器映射到恰當的組件元素上。瀏覽器

監聽事件

在 React 中監聽事件簡單以下:babel

class ShowAlert extends React.Component {
  showAlert() {
    alert("Im an alert");
  }

  render() {
    return <button onClick={this.showAlert}>show alert</button>;
  }
}
複製代碼

在上面的例子中,onClick 屬性是咱們的事件處理程序,它被添加到目標元素上以便在元素被點擊時執行要被執行的函數。onClick 屬性設置了 showAlert 函數。ide

簡單點兒說,就是不管什麼時候點擊該按鈕,showAlert 函數都會被調用並顯示一條信息。函數

綁定方法

在 JavaScript 中,類方法並非默認綁定的。所以,將函數綁定到類的實例上十分重要。post

render() 中綁定

這種方式是在 render 函數中調用 bind 方法來進行綁定的:性能

class ChangeInput extends Component {
  constructor(props) {
    super(props);
    this.state = {
      name: ""
    };
  }

  changeText(event) {
    this.setState({
      name: event.target.value
    });
  }

  render() {
    return (
      <div> <label htmlFor="name">Enter Text here </label> <input type="text" id="name" onChange={this.changeText.bind(this)} /> <h3>{this.state.name}</h3> </div> ); } } 複製代碼

在上面的例子中,咱們使用 onChange事件處理程序在 input 輸入框上監聽鍵盤事件,該操做是經過在 render 函數中綁定完成的。該方法須要在 render 函數中調用.bind(this)

爲啥呢?

任何 ES6 類中的方法都是普通的 JavaScript 函數,所以其都從 Function 的原型上繼承 bind() 方法。如今,當咱們在 JSX 內部調用 onChange 時,this 會指向咱們的組件實例。

使用這種方法可能會形成一些潛在的性能問題,由於函數在每次 render 後都被從新分配一次。這種性能代價可能在小型 React 應用上並不明顯,但在較大應用上就要值得注意了。

constructor() 中綁定

若是說在 render 中綁定的方法不適合你,你也能夠在 constructor() 中進行綁定。例子以下:

class ChangeInput extends Component {
  constructor(props) {
    super(props);
    this.state = {
      name: ""
    };

    this.changeText = this.changeText.bind(this);
  }

  changeText(event) {
    this.setState({
      name: event.target.value
    });
  }

  render() {
    return (
      <div> <label htmlFor="name">Enter Text here </label> <input type="text" id="name" onChange={this.changeText} /> <h3>{this.state.name}</h3> </div> ); } } 複製代碼

如你所見,changeText 函數綁定在 constructor 上:

this.changeText = this.changeText.bind(this)
複製代碼

等號左邊的 this.changeText 指向 changeText 方法,因爲該步操做是在 constructor 中完成的,因此 this 指向 ChangeInput組件。

等號右邊的 this.changeText 指向相同的 changeText 方法,可是咱們如今在其上調用了 .bind() 方法。

括號中的 this 做爲咱們傳入 .bind() 中的參數指向的是上下文(context),也就是指向 ChangeInput組件。

一樣值得注意的是若是 changeText 不綁定到組件實例上的話,它就不能訪問 this.setState,由於這時的 this 會是 undefined

使用箭頭函數進行綁定

綁定事件處理函數的另外一種方式是經過箭頭函數。經過這種 ES7 的類特性(實驗性的public class fields 語法),咱們能夠在方法定義時就進行事件綁定,例子以下:

class ChangeInput extends Component {
  handleEvent = event => {
    alert("I was clicked");
  };

  render() {
    return (
      <div> <button onClick={this.handleEvent}>Click on me</button> </div>
    );
  }
}
複製代碼

箭頭函數表達式語法比傳統的函數表達式簡短且沒有本身的 thisargumentssupernew.target

在上面的例子中,一旦組件被建立,this.handleEvent就不會再有變化了。這種方法很是簡單且容易閱讀。

同在 render 函數中綁定的方法同樣,這種方法也有其性能代價。

使用匿名箭頭函數在 render 中綁定

綁定的時候定義一個匿名函數(箭頭函數),將匿名函數與元素綁定,而不是直接綁定事件處理函數,這樣 this 在匿名函數中就不是 undefined 了:

class LoggingButton extends React.Component {
  handleClick() {
    console.log('this is:', this);
  }
 
  render() {
    return (
      <button onClick={(e) => this.handleClick(e)}> Click me </button>
    );
  }
}
複製代碼

這種方法有一個問題,每次 LoggingButton 渲染的時候都會建立一個新的 callback 匿名函數。在這個例子中沒有問題,可是若是將這個 onClick 的值做爲 props 傳給子組件的時候,將會致使子組件從新 render,因此不推薦。

定製組件和事件

每當談到 React 中的事件,只有 DOM 元素能夠有事件處理程序。舉個栗子,好比說如今有個組件叫 CustomButton,其有一個 onClick 事件,可是當你點擊時不會有任何反應,緣由就是前面所說的。

那麼咱們要如何處理定製組件中的事件綁定呢?

答案就是經過在 CustomButton 組件中渲染一個 DOM 元素而後把 onClick 做爲 prop 傳進去,CustomButton 組件實際上只是爲點擊事件充當了傳遞介質。

class CustomButton extends Component {
  render() {
    const { onPress, children } = this.props;

    return (
      <button type="button" onClick={onPress}> {children} </button>
    );
  }
}

class ChangeInput extends Component {
  handleEvent = () => {
    alert("I was clicked");
  };

  render() {
    return (
      <div> <CustomButton onPress={this.handleEvent}>Click on me</CustomButton> </div>
    );
  }
}
複製代碼

本例中,CustomButton 組件接收了一個叫 onPress 的prop,而後又給 button 傳入了一個 onClick

向事件處理程序傳遞參數

給事件處理程序傳遞額外參數是很常見的,好比 id 是行 ID,下面兩種傳參方式均可以:

<button onClick={(e)=>this.deleteRow(id, e)}>Delete Row</button>

<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>
複製代碼

上面兩種傳參方式是等價的。

在兩種傳參方式中,參數 e 都表明 React 事件將要做爲參數 id 後面的第二個參數來傳遞。區別在於使用箭頭函數時,參數 e 要顯示傳遞,可是使用 bind 的話,事件對象以及更多的參數將會被隱式的進行傳遞。

參考

A guide to React onClick event handlers

事件處理

React 事件綁定的正確姿式

相關文章
相關標籤/搜索