用 React 元素處理事件和在DOM元素里處理事件非常相似绳军。有一些語(yǔ)法差異:
- React 事件使用駝峰式命名哄褒,而不是小寫
- 用JSX依许,你能傳遞函數(shù)作為事件處理器,而不是一個(gè)字符串
HTML:
<button onclick="activateLasers()">
Activate Lasers
</button>
React:
<button onClick={activateLasers}>
Activate Lasers
</button>
另外一個(gè)區(qū)別刽沾,在 React 中本慕,不能用 return false
阻止默認(rèn)行為。必須直接調(diào)用 preventDefault
例如侧漓,用純HTML锅尘,為了防止打開新頁(yè)面的默認(rèn)鏈接行為,可以這樣:
<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
是一個(gè)合成事件布蔗,React 根據(jù) W3C spec
定義這些合成事件藤违,所以不需要擔(dān)心瀏覽器的兼容性。
備注:合成事件--是一個(gè)跨瀏覽器原生事件包裝器纵揍,它具有與瀏覽器原生事件相同的接口顿乒,包括 stopPropagation() 和 preventDefault() ,除了原生事件在所有瀏覽器中泽谨,他們工作方式都相同璧榄。
當(dāng)使用 React 時(shí),通常不需要調(diào)用 addEventListener
對(duì)創(chuàng)建后的DOM元素添加監(jiān)聽器吧雹。相反骨杂,當(dāng)元素最初被渲染時(shí),僅需提供一個(gè)監(jiān)聽器雄卷。
當(dāng)使用 ES6 class
定義一個(gè)組件搓蚪,一個(gè)常見的模式是一個(gè)事件處理器在類中是一個(gè)方法。例如丁鹉,toggle
組件渲染讓用戶在 ON
和 OFF
之間切換的按鈕:
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = {isToggleOn: true};
// 此綁定是必需的妒潭,讓 `this` 在回調(diào)里生效
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回調(diào)中,你必須注意 this
的指向揣钦。在 Javascript中雳灾,類方法沒(méi)有被默認(rèn)綁定。如果你沒(méi)有綁定 this.handleClick
并把它傳遞到 onClick
拂盯,則函數(shù)被實(shí)際調(diào)用時(shí)佑女,this
將會(huì)是 undefined
。
這不是 React 特有的行為谈竿;這是Javascript中函數(shù)如何工作的一部份团驱,通常,如果在它后面提供一個(gè)沒(méi)有 ()
方法空凸,像onClick={this.handleClick}
嚎花,你就應(yīng)該綁定( bind
) 該方法。
如果你不想調(diào)用 bind
呀洲,有兩種方式能解決它紊选。如果使用試驗(yàn)性 public class fields syntax啼止,可以用類字段正確的綁定回調(diào):
class LoggingButton extends React.Component {
// 這個(gè)語(yǔ)法確保 `this` 被綁定在handleClick中
// 警告: 這是 *試驗(yàn)性* 語(yǔ)法
handleClick = () => {
console.log('this is:', this);
}
render() {
return (
<button onClick={this.handleClick}>
Click me
</button>
);
}
}
此語(yǔ)法在創(chuàng)建 React APP 中是默認(rèn)開啟的。
如果不用類字段語(yǔ)法兵罢,也可以在回調(diào)中庸一個(gè)箭頭函數(shù):
class LoggingButton extends React.Component {
handleClick() {
console.log('this is:', this);
}
render() {
// 這個(gè)語(yǔ)法確保 `this` 被綁定在handleClick中
return (
<button onClick={(e) => this.handleClick(e)}>
Click me
</button>
);
}
}
這個(gè)語(yǔ)法的問(wèn)題是每次 LoggingButton
渲染時(shí)都會(huì)創(chuàng)建一個(gè)不同的回調(diào)献烦。大多數(shù)情況下,這沒(méi)問(wèn)題卖词。但是巩那,如果回調(diào)被當(dāng)作 prop
傳遞給子組件,這些組件可能做額外重復(fù)渲染此蜈。我們通常推薦綁定在構(gòu)造函數(shù)中或者使用類字段語(yǔ)法即横,避免這種性能問(wèn)題。
將實(shí)參傳遞給事件處理器
在循環(huán)內(nèi)部裆赵,通常想把額外的形參傳遞給事件處理器东囚。列如,如果 id
是行ID战授,以下二者都可以工作:
<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>
上面二行是等價(jià)的页藻,使用 箭頭函數(shù) 和 Function.prototype.bind
在這兩者情況下,e
實(shí)參表示 React 事件將作為ID后第二個(gè)實(shí)參傳遞陈醒。使用箭頭函數(shù)惕橙,我們必須傳遞它,但是用 bind
綁定的任何的參數(shù)會(huì)被自動(dòng)的轉(zhuǎn)發(fā)钉跷。