大家周末好特石,2016年的最后幾篇文章開始寫到了React的一些東西吊说,那么最近就來一些圖表君對于React的簡單總結(jié)和理解,那么今天就開始第一篇钓瞭,說一說React的事件系統(tǒng)。
總覽
簡單來說React實現(xiàn)了一個SyntheticEvent層淫奔,所有定義的事件處理器都可以接受到一個SyntheticEvent對象的實例山涡,他是一個跨瀏覽器的對于原生事件的包裝,和原生事件一樣有同樣的接口,包括stopPropagation()和preventDefault()鸭丛。
合成事件的使用方式
在React中不會把所有的事件處理器綁定到相應(yīng)的真實的DOM節(jié)點上竞穷,而是使用一個統(tǒng)一的事件監(jiān)聽器,把所有的事件綁定在最外層鳞溉。當(dāng)事件發(fā)生的時候瘾带,首先被這個統(tǒng)一的事件監(jiān)聽器處理,隨后找到真正的事件處理函數(shù)進行調(diào)用熟菲,這樣是為了提高效率月弛,這是因為在UI系統(tǒng)中,事件處理器越多科盛,那么占據(jù)的內(nèi)存就越大帽衙,React的做法是將其簡化為一個,這樣就大大提高了效率贞绵。在之前開發(fā)者需要為了優(yōu)化性能需要自己來優(yōu)化自己的事件處理器的代碼厉萝,現(xiàn)在React幫助你完成了這些工作。
合成事件的綁定方式
說了這么許多理論上的知識榨崩,我們來看看合成事件是怎么使用的谴垫。
-
bind方法。
我們來直接看代碼
import React, {Component} from 'react';
class EventApp extends Component {
handleClick(e,args){
console.log('this is the react event',e)
console.log('this is the args', args)
}
render(){
return <button onClick={this.handleClick.bind(this,'test')}>Test</button>
}
}
-
構(gòu)造器內(nèi)聲明
再來看代碼
import React, {Component} from 'react';
class EventApp extends Component {
constructor(props){
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick(e){
console.log('this is the react event',e)
}
render(){
return <button onClick={this.handleClick}>Test</button>
}
}
使用構(gòu)造器內(nèi)聲明的方法母蛛,僅僅要綁定一次而不需要每次使用的時候都綁定一次翩剪。
- 箭頭函數(shù)
class ButtonApp extends React.Component {
handleClick (e) {
console.log(e.target.value)
}
render(){
return <button onClick={(e) => this.handleClick(e)}>Test</button>;
}
}
從上邊的使用方式我們可以看出React來使用合成事假還是很簡單的,但是現(xiàn)實的世界總是更加的復(fù)雜的彩郊。那么在React中我們可以使用原始事件嗎前弯?當(dāng)然是可以的。
使用原生事件
在React中我們也可以使用原生事件秫逝,那么如何進行綁定呢恕出,因為React提供了ComponentDidMount這樣的API讓我們可以調(diào)用,那么要使用原生事件我們就可以在DidMount后進行綁定违帆。例如上邊的那個例子中如果我們想把click事件綁定在原生button上該怎么做呢浙巫?我們來看代碼:
class ButtonApp extends React.Component {
componentDidMount(){
this.refs.button.addEventListener('click' e => {
console.log(e);
})
}
componentWillUnmount(){
this.refs.button.removeEventListener('click')
}
render(){
return <button ref="button">Test</button>
}
}
在這里例子中我們使用原生事件的方法綁到了button上,注意一點的是在DidMount上add了這個listener在willUnmont上remove這個listener刷后。一定要手動的記住移除的畴,不然可能會出現(xiàn)內(nèi)存泄漏問題。如果我們使用React合成事件尝胆,這些事React已經(jīng)幫你做好了丧裁。但是現(xiàn)實的情況下我們有一些場景是不得不用到原生的事件的那么該怎么做呢?
我們來看下邊的一個例子班巩。例如我們要實現(xiàn)這樣的一個功能渣慕,在頁面上有個button嘶炭,當(dāng)點擊它會出現(xiàn)一個圖片。當(dāng)點擊頁面的其他部分的時候逊桦,這個圖片會自動的消失眨猎,那么這樣的需求我們就不得不使用原生的事件了。話不多說我們來看代碼實現(xiàn)强经。
import React from 'react';
class App extends React.Component {
constructor(props){
super(props);
this.state = {
show: false
}
this.handleClick = this.handleClick.bind(this)
this.handleClickImage = this.handleClickImage.bind(this);
}
handleClick(){
this.setState({
show: true
})
}
componentDidMount(){
document.body.addEventListener('click', e=> {
this.setState({
show: false
})
})
}
componentWillUnmount(){
document.body.removeEventListener('click');
}
render(){
return (
<div className="container">
<button onClick={this.handleClick}>Open Image</button>
<div className="img-container" style={{ display: this.state.show ? 'block': 'none'}} >
![](http://upload-images.jianshu.io/upload_images/65230-86cf2d60ac48f213.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
</div>
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('root'));
上邊一個例子中睡陪,我們實現(xiàn)了組件APP,他里邊有一個button匿情,它上邊有一個handleClick的事件處理器兰迫,當(dāng)觸發(fā)時會把app的state里show制成true,這樣圖片就顯示了出來炬称。同時在body上使用了原生事件汁果,當(dāng)發(fā)生點擊事件的時候,就會被收起玲躯,這樣就簡單實現(xiàn)了需求的功能据德,那是看似這樣好像就沒有問題的,但是這其中有個bug跷车,到底是什么問題呢棘利,我們下篇文章繼續(xù)。看看原生事件和合成事件混用的那些事。
參考文獻:
深入react技術(shù)棧