React 事件處理
React 元素的事件處理和 DOM 元素類似荡短。但是有一點(diǎn)語(yǔ)法上的不同:
- React 事件綁定屬性的命名采用駝峰式寫法,而不是小寫类垫。
- 如果采用 JSX 的語(yǔ)法你需要傳入一個(gè)函數(shù)作為事件處理函數(shù)培廓,而不是一個(gè)字符串(DOM 元素的寫法)
HTML 通常寫法是:
<button onclick="activateLasers()">
激活按鈕
</button>
React 中寫法為:
<button onClick={activateLasers}>
激活按鈕
</button>
在 React 中另一個(gè)不同是你不能使用返回 false 的方式阻止默認(rèn)行為, 你必須明確的使用 preventDefault
误褪。
例如责鳍,通常我們?cè)?HTML 中阻止鏈接默認(rèn)打開(kāi)一個(gè)新頁(yè)面,可以這樣寫:
<a href="#" onclick="console.log('點(diǎn)擊鏈接'); return false">
點(diǎn)我
</a>
在 React 的寫法為:
function ActionLink() {
function handleClick(e) {
e.preventDefault();
console.log('鏈接被點(diǎn)擊');
}
return (
<a href="#" onClick={handleClick}>
click me
</a>
);
}
實(shí)例中 e 是一個(gè)合成事件兽间。
使用 React 的時(shí)候通常你不需要使用 addEventListener 為一個(gè)已創(chuàng)建的 DOM 元素添加監(jiān)聽(tīng)器历葛。你僅僅需要在這個(gè)元素初始渲染的時(shí)候提供一個(gè)監(jiān)聽(tīng)器。
當(dāng)你使用 ES6 class 語(yǔ)法來(lái)定義一個(gè)組件的時(shí)候嘀略,事件處理器會(huì)成為類的一個(gè)方法恤溶。例如乓诽,下面的 Toggle 組件渲染一個(gè)讓用戶切換開(kāi)關(guān)狀態(tài)的按鈕:
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = {isToggleOn: true};
// 這邊綁定是必要的,這樣 `this` 才能在回調(diào)函數(shù)中使用
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')
);
你必須謹(jǐn)慎對(duì)待 JSX 回調(diào)函數(shù)中的 this咒程,類的方法默認(rèn)是不會(huì)綁定 this 的问裕。如果你忘記綁定 this.handleClick 并把它傳入 onClick, 當(dāng)你調(diào)用這個(gè)函數(shù)的時(shí)候 this 的值會(huì)是 undefined。
這并不是 React 的特殊行為孵坚;它是函數(shù)如何在 JavaScript 中運(yùn)行的一部分粮宛。通常情況下,如果你沒(méi)有在方法后面添加 () 卖宠,例如 onClick={this.handleClick}
巍杈,你應(yīng)該為這個(gè)方法綁定 this。
如果使用 bind 讓你很煩扛伍,這里有兩種方式可以解決筷畦。如果你正在使用實(shí)驗(yàn)性的屬性初始化器語(yǔ)法,你可以使用屬性初始化器來(lái)正確的綁定回調(diào)函數(shù):
class LoggingButton extends React.Component {
// 這個(gè)語(yǔ)法確保了 `this` 綁定在 handleClick 中
// 這里只是一個(gè)測(cè)試
handleClick = () => {
console.log('this is:', this);
}
render() {
return (
<button onClick={this.handleClick}>
Click me
</button>
);
}
}
如果你沒(méi)有使用屬性初始化器語(yǔ)法刺洒,你可以在回調(diào)函數(shù)中使用 箭頭函數(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ǔ)法有個(gè)問(wèn)題就是每次 LoggingButton
渲染的時(shí)候都會(huì)創(chuàng)建一個(gè)不同的回調(diào)函數(shù)鳖宾。在大多數(shù)情況下,這沒(méi)有問(wèn)題逆航。然而如果這個(gè)回調(diào)函數(shù)作為一個(gè)屬性值傳入低階組件鼎文,這些組件可能會(huì)進(jìn)行額外的重新渲染。我們通常建議在構(gòu)造函數(shù)中綁定或使用屬性初始化器語(yǔ)法來(lái)避免這類性能問(wèn)題因俐。
向事件處理程序傳遞參數(shù)
通常我們會(huì)為事件處理程序傳遞額外的參數(shù)拇惋。例如,若是 id 是你要?jiǎng)h除那一行的 id抹剩,以下兩種方式都可以向事件處理程序傳遞參數(shù):
<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>
上述兩種方式是等價(jià)的撑帖。
上面兩個(gè)例子中,參數(shù) e
作為 React 事件對(duì)象將會(huì)被作為第二個(gè)參數(shù)進(jìn)行傳遞澳眷。通過(guò)箭頭函數(shù)的方式胡嘿,事件對(duì)象必須顯式的進(jìn)行傳遞,但是通過(guò) bind
的方式钳踊,事件對(duì)象以及更多的參數(shù)將會(huì)被隱式的進(jìn)行傳遞衷敌。
值得注意的是,通過(guò) bind
方式向監(jiān)聽(tīng)函數(shù)傳參箍土,在類組件中定義的監(jiān)聽(tīng)函數(shù)逢享,事件對(duì)象 e
要排在所傳遞參數(shù)的后面,例如:
class Popper extends React.Component{
constructor(){
super();
this.state = {name:'Hello world!'};
}
preventPop(name, e){ //事件對(duì)象e要放在最后
e.preventDefault();
alert(name);
}
render(){
return (
<div>
<p>hello</p>
{/* 通過(guò) bind() 方法傳遞參數(shù)吴藻。 */}
<a onClick={this.preventPop.bind(this,this.state.name)}>Click</a>
</div>
);
}
}