React元素處理事件和DOM元素處理事件很類似。下面是一些語法的不同之處:
- React事件的命名是用駝峰命名,而不是小寫字母。
- 利用JSX你傳遞一個函數作為事件處理器,而不是一個字符串。
舉個例子,這是一段HTML:
<button onclick="activateLasers()">
Activate Lasers
</button>
而在React中略微有些不同:
<button onClick={activateLasers}>
Activate Lasers
</button>
另一個不同之處就是在React中你不能通過返回false來阻止事件默認的行為。你必須調用preventDefault。舉個例子,一個簡單的頁面,為了阻止默認的鏈接行為打開一個新頁面,你可以這樣寫:
<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標准來定義這些綜合事件,所以你可以不用擔心跨瀏覽器兼容性問題。看看SyntheticEvent手冊學習更多知識。
當使用React你通常不需要調用addEventListener來向一個被創建的DOM元素添加事件監聽器。只需要當元素首次被渲染的時候提供一個監聽器。
當你使用ES6的類定義了一個組件,一個相同的模式就是一個事件監聽器會是類的一個方法。舉個例子,這個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);
//bind方法會將函數handleClick的this設置為提供的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。
這並不是React的特殊行為;而是函數如何在js中工作的一部分。通常,如果你涉及到了一個后面沒有()的方法,就像onClick={this.handleClick},你應該為那個函數調用bind方法改變它的this。
如果調用bind使你厭煩,還有兩種方法可以避免使用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> ); } }
<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> ); } }
