事件處理程序(Event handlers)就是每當有事件被觸發時決定要執行的動做或行爲。javascript
在 React 應用中,事件名使用小駝峯格式書寫,意思就是 onclick
要寫成 onClick
。html
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>
);
}
}
複製代碼
箭頭函數表達式語法比傳統的函數表達式簡短且沒有本身的 this
、arguments
、super
和 new.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
的話,事件對象以及更多的參數將會被隱式的進行傳遞。