淺析React之事件系統(tǒng)(二)

上篇文章中,我們談到了React事件系統(tǒng)的實(shí)現(xiàn)方式嘿悬,和在React中使用原生事件的方法低零,那么這篇文章我們來(lái)繼續(xù)分析下婆翔,看看React中合成事件和原生事件混用的各種情況。

上一個(gè)例子

在上篇文章中掏婶,我們舉了個(gè)例子啃奴。為了防止大家不記得,我們來(lái)看看那個(gè)例子的代碼雄妥。

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');
  }
  
  handleClickImage(e){
    console.log('in this ')
    e.stopPropagation();
  }
  
  render(){
    return (
      <div className="container">
        <button onClick={this.handleClick}>Open Image</button>
          <div className="img-container" style={{ display: this.state.show ? 'block': 'none'}} onClick={this.handleClickImage}>
            ![](http://upload-images.jianshu.io/upload_images/65230-3ad92c3b2a23e6b5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
          </div>
      </div>
    )
  }
}
ReactDOM.render(<App />, document.getElementById('root'));

這有什么問(wèn)題呢最蕾? 問(wèn)題就在于,如果我們點(diǎn)擊image的內(nèi)部依舊可以收起Image老厌,那么這是為什么呢揖膜?這是因?yàn)槲覀兗皶r(shí)點(diǎn)擊了Image的內(nèi)部,body上綁定的事件處理器依舊會(huì)執(zhí)行梅桩,這樣就讓我們的image收起來(lái)了。那我們?nèi)绻幌胱宨mage收起來(lái)改怎么做呢拜隧?

首先的想法是停止冒泡宿百,如果我們?cè)趇mg-container中就停止冒泡了是不是就可以讓image不消失了呢?比如這樣:

...
handleClickImage(e){
    e.preventDefault();
    e.stopPropagation();
  }
  
  render(){
    return (
      <div className="container">
        <button onClick={this.handleClick}>Open Image</button>
          <div className="img-container" style={{ display: this.state.show ? 'block': 'none'}} onClick={this.handleClickImage}>
            ![](http://upload-images.jianshu.io/upload_images/65230-3ad92c3b2a23e6b5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
          </div>
      </div>
    )
  }
...

Open In CodePen

在這里我們定義一個(gè)handleClickImage的方法洪添,在其中我們執(zhí)行取消默認(rèn)行為和停止冒泡垦页。那是似乎效果并不是我們想要的。因?yàn)樽柚筊eact事件冒泡的行為只能用于React合成事件中干奢,沒(méi)法阻止原生事件的冒泡痊焊。同樣用React.NativeEvent.stopPropagation()也是無(wú)法阻止冒泡的。

如何解決這樣的問(wèn)題呢忿峻?首先薄啥,盡量的避免混用合成事件和原生事件。需要注意的點(diǎn)是:

  1. 阻止react 合成事件冒泡并不會(huì)阻止原生時(shí)間的冒泡逛尚,從上邊的例子我們已經(jīng)看到了垄惧,及時(shí)使用stopPropagation也是無(wú)法阻止原生時(shí)間的冒泡的。
  2. 第二點(diǎn)需要注意的是绰寞,取消原生時(shí)間的冒泡會(huì)同時(shí)取消React Event到逊。并且原生事件的冒泡在react event的觸發(fā)和冒泡之前。同時(shí)React Event的創(chuàng)建和冒泡是在原生事件冒泡到最頂層的component之后的滤钱。我們來(lái)看這個(gè)例子:
class App extends React.Component {
  
  render(){
   return <GrandPa />;
  }
}

class GrandPa extends React.Component {
  constructor(props){
      super(props);
      this.state = {clickTime: 0};
      this.handleClick = this.handleClick.bind(this);
  }
  
 handleClick(){
   console.log('React Event grandpa is fired');
  this.setState({clickTime: new Date().getTime()})
};
  
  componentDidMount(){
    document.getElementById('grandpa').addEventListener('click',function(e){
      console.log('native Event GrandPa is fired');
    })
  }
  
  render(){
    return (
      <div id='grandpa' onClick={this.handleClick}>
        <p>GrandPa Clicked at: {this.state.clickTime}</p>
        <Dad />
      </div>
    )
  }
}

class Dad extends React.Component {
  constructor(props){
    super(props);
    this.state = {clickTime:0};
    this.handleClick=this.handleClick.bind(this);
  }
  
  componentDidMount(){
    document.getElementById('dad').addEventListener('click',function(e){
      console.log('native Event Dad is fired');
      e.stopPropagation();
    })
  }
  
  handleClick(){
    console.log('React Event Dad is fired')
    this.setState({clickTime: new Date().getTime()})
  }
  
  render(){
    return (
      <div id='dad' onClick={this.handleClick}>
       <p>Dad Clicked at: {this.state.clickTime}</p>
        <Son />
      </div>
     )
  }
}

class Son extends React.Component {
  constructor(props){
    super(props);
    this.state = {clickTime:0};
    this.handleClick=this.handleClick.bind(this);
  }
  
  handleClick(){
    console.log('React Event Son is fired');
    this.setState({clickTime: new Date().getTime()})
  }
  
  componentDidMount(){
    document.getElementById('son').addEventListener('click',function(e){
      console.log('native Event son is fired');
    })
  }
  
  render(){
    return (
      <div id="son">
       <p onClick={this.handleClick}>Son Clicked at: {this.state.clickTime} </p>
      </div>
     )
  }
}

ReactDOM.render(<App />, document.getElementById('root'));

Open in CodePen

在這個(gè)例子中我們有三個(gè)component觉壶,Son Dad,Grandpa件缸。同時(shí)定義了React Event handler 和 native event handler铜靶,并在Dad的native Event handler中stopPropagation,當(dāng)我們點(diǎn)擊Son or Dad component的時(shí)候會(huì)發(fā)現(xiàn)停团,React Event handler并沒(méi)有被trigger旷坦。
console里的output為:

"native Event son is fired"
"native Event Dad is fired"

這就說(shuō)明native Event的停止冒泡可以阻斷所有的React Event掏熬。所以即使我們是在Dad上停止冒泡的,依舊阻斷了Son上的React Event秒梅。

同時(shí)如果我們把dad上的stopPropagation remove掉我們會(huì)看到如下結(jié)果:

"native Event son is fired"
"native Event Dad is fired"
"native Event GrandPa is fired"
"React Event Son is fired"
"React Event Dad is fired"
"React Event grandpa is fired"

這就說(shuō)明React的合成時(shí)間是在原生事件冒泡到最頂層組件結(jié)束后才創(chuàng)建和冒泡的旗芬,也是符合React的原理,因?yàn)樵谑菍?shí)現(xiàn)的時(shí)候React只是將一個(gè)Event listener 掛在了最頂層的組件上捆蜀,其內(nèi)部一套自己的機(jī)制進(jìn)行事件的管理疮丛。

淺析React之事件系統(tǒng)(一)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市辆它,隨后出現(xiàn)的幾起案子誊薄,更是在濱河造成了極大的恐慌,老刑警劉巖锰茉,帶你破解...
    沈念sama閱讀 206,602評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件呢蔫,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡飒筑,警方通過(guò)查閱死者的電腦和手機(jī)片吊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)协屡,“玉大人俏脊,你說(shuō)我怎么就攤上這事》粝” “怎么了爷贫?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,878評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)补憾。 經(jīng)常有香客問(wèn)我漫萄,道長(zhǎng),這世上最難降的妖魔是什么余蟹? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,306評(píng)論 1 279
  • 正文 為了忘掉前任卷胯,我火速辦了婚禮,結(jié)果婚禮上威酒,老公的妹妹穿的比我還像新娘窑睁。我一直安慰自己,他們只是感情好葵孤,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,330評(píng)論 5 373
  • 文/花漫 我一把揭開(kāi)白布担钮。 她就那樣靜靜地躺著,像睡著了一般尤仍。 火紅的嫁衣襯著肌膚如雪箫津。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,071評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音苏遥,去河邊找鬼饼拍。 笑死,一個(gè)胖子當(dāng)著我的面吹牛田炭,可吹牛的內(nèi)容都是我干的师抄。 我是一名探鬼主播,決...
    沈念sama閱讀 38,382評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼教硫,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼叨吮!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起瞬矩,我...
    開(kāi)封第一講書(shū)人閱讀 37,006評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤茶鉴,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后景用,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體涵叮,經(jīng)...
    沈念sama閱讀 43,512評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,965評(píng)論 2 325
  • 正文 我和宋清朗相戀三年伞插,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了围肥。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,094評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蜂怎,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出置尔,到底是詐尸還是另有隱情杠步,我是刑警寧澤,帶...
    沈念sama閱讀 33,732評(píng)論 4 323
  • 正文 年R本政府宣布榜轿,位于F島的核電站幽歼,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏谬盐。R本人自食惡果不足惜甸私,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,283評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望飞傀。 院中可真熱鬧皇型,春花似錦、人聲如沸砸烦。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,286評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)幢痘。三九已至唬格,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背购岗。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,512評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工汰聋, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人喊积。 一個(gè)月前我還...
    沈念sama閱讀 45,536評(píng)論 2 354
  • 正文 我出身青樓烹困,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親注服。 傳聞我的和親對(duì)象是個(gè)殘疾皇子韭邓,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,828評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 版權(quán)聲明:本文為博主原創(chuàng)文章女淑,未經(jīng)博主允許不得轉(zhuǎn)載。 PS:轉(zhuǎn)載請(qǐng)注明出處作者:TigerChain地址:http...
    TigerChain閱讀 8,368評(píng)論 1 9
  • 本文通過(guò)一個(gè)簡(jiǎn)短的實(shí)例&控制臺(tái)調(diào)試辜御,了解react事件處理的全過(guò)程鸭你。下面是測(cè)試用代碼,使用控制臺(tái)可以清晰看到函數(shù)執(zhí)...
    溪離欣洛閱讀 1,198評(píng)論 2 2
  • JavaScript 程序采用了異步事件驅(qū)動(dòng)編程模型擒权。在這種程序設(shè)計(jì)風(fēng)格下袱巨,當(dāng)文檔、瀏覽器碳抄、元素或與之相關(guān)的對(duì)象發(fā)...
    劼哥stone閱讀 1,251評(píng)論 3 11
  • 1 React合成事件特點(diǎn) React自己實(shí)現(xiàn)了一套高效的事件注冊(cè)愉老,存儲(chǔ),分發(fā)和重用邏輯剖效,在DOM事件體系基礎(chǔ)上做...
    Dabao123閱讀 1,681評(píng)論 1 1
  • 時(shí)光流入罅隙,細(xì)細(xì)一數(shù)十年過(guò)去爷光。 親愛(ài)的你垫竞,十年前,是幾歲呢蛀序? 而我, 12歲欢瞪,四年級(jí)。 ...
    清歡不二閱讀 816評(píng)論 1 2