成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

React事件機(jī)制

lavnFan / 3229人閱讀

摘要:注冊(cè)事件的回調(diào)函數(shù)由來統(tǒng)一管理,根據(jù)事件的類型和組件標(biāo)識(shí)為唯一標(biāo)識(shí)事件并進(jìn)行存儲(chǔ)。利用中注入的例如會(huì)將原生的事件轉(zhuǎn)化成合成的事件,然后批量執(zhí)行存儲(chǔ)的回調(diào)函,回調(diào)函數(shù)的執(zhí)行分為兩步,第一步是將所有的合成事件放到事件隊(duì)列里面,第二步是逐個(gè)執(zhí)行。

  最近在閱讀《深入React技術(shù)棧》一書中,發(fā)現(xiàn)了之前使用React中并沒有注意到的React事件與瀏覽器原生事件之間的區(qū)別,鑒于好久已經(jīng)沒有寫東西了,就想寫一下關(guān)于React事件的文章。
  首先我們舉個(gè)例子,如果我們需要實(shí)現(xiàn)一個(gè)組件,這個(gè)組件點(diǎn)擊按鈕會(huì)顯示一個(gè)二維碼,點(diǎn)擊二維碼之外的區(qū)域可以隱藏二維碼,但是點(diǎn)擊二維碼本身卻不會(huì)關(guān)閉,代碼如下:

//代碼來源于《深入React技術(shù)?!?.1.4節(jié)
class QrCode extends Component {
  constructor(props) {
    super(props);
    this.handleClick = this.handleClick.bind(this);
    this.handleClickQr = this.handleClickQr.bind(this);
    this.state = {
      active: false,
    };
  }
  
  componentDidMount() {
    document.body.addEventListener("click", e => {
      this.setState({
        active: false,
      });
    });
  }

  componentWillUnmount() {
    document.body.removeEventListener("click");
  }
  
  handleClick() {
    this.setState({
      active: !this.state.active,
    });
  }
  
  handleClickQr(e) {
    e.stopPropagation();
  }

  render() {
    return (
      
); } }

  上面代碼從感官上感覺確實(shí)可以實(shí)現(xiàn)要求的組件,但事實(shí)上我們運(yùn)行上述代碼可以發(fā)現(xiàn),點(diǎn)擊二維碼本身也會(huì)導(dǎo)致二維碼的隱藏,現(xiàn)在就有意思了,我們來仔細(xì)分析一下。
  其實(shí)React事件并沒有原生的綁定在真實(shí)的DOM上,而是使用了行為委托方式實(shí)現(xiàn)事件機(jī)制。
  

  如上圖所示,在JavaScript中,事件的觸發(fā)實(shí)質(zhì)上是要經(jīng)過三個(gè)階段:事件捕獲、目標(biāo)對(duì)象本身的事件處理和事件冒泡,假設(shè)在div中觸發(fā)了click事件,實(shí)際上首先經(jīng)歷捕獲階段會(huì)由父級(jí)元素將事件一直傳遞到事件發(fā)生的元素,執(zhí)行完目標(biāo)事件本身的處理事件后,然后經(jīng)歷冒泡階段,將事件從子元素向父元素冒泡。正因?yàn)槭录贒OM的傳遞經(jīng)歷這樣一個(gè)過程,從而為行為委托提供了可能。通俗地講,行為委托的實(shí)質(zhì)就是將子元素事件的處理委托給父級(jí)元素處理。React會(huì)將所有的事件都綁定在最外層(document),使用統(tǒng)一的事件監(jiān)聽,并在冒泡階段處理事件,當(dāng)掛載或者卸載組件時(shí),只需要在通過的在統(tǒng)一的事件監(jiān)聽位置增加或者刪除對(duì)象,因此可以提高效率。
  并且React并沒有使用原生的瀏覽器事件,而是在基于Virtual DOM的基礎(chǔ)上實(shí)現(xiàn)了合成事件(SyntheticEvent),事件處理程序接收到的是SyntheticEvent的實(shí)例。SyntheticEvent完全符合W3C的標(biāo)準(zhǔn),因此在事件層次上具有瀏覽器兼容性,與原生的瀏覽器事件一樣擁有同樣的接口,可以通過stopPropagation()preventDefault()相應(yīng)的中斷。如果需要訪問當(dāng)原生的事件對(duì)象,可以通過引用nativeEvent獲得。
  
  上圖為大致的React事件機(jī)制的流程圖,React中的事件機(jī)制分為兩個(gè)階段:事件注冊(cè)和事件觸發(fā):

事件注冊(cè)  
  React在組件加載(mount)和更新(update)時(shí),其中的ReactDOMComponent會(huì)對(duì)傳入的事件屬性進(jìn)行處理,對(duì)相關(guān)事件進(jìn)行注冊(cè)和存儲(chǔ)。document中注冊(cè)的事件不處理具體的事件,僅對(duì)事件進(jìn)行分發(fā)。ReactBrowserEventEmitter作為事件注冊(cè)入口,擔(dān)負(fù)著事件注冊(cè)和事件觸發(fā)。注冊(cè)事件的回調(diào)函數(shù)由EventPluginHub來統(tǒng)一管理,根據(jù)事件的類型(type)和組件標(biāo)識(shí)(_rootNodeID)為key唯一標(biāo)識(shí)事件并進(jìn)行存儲(chǔ)。

事件執(zhí)行
  事件執(zhí)行時(shí),document上綁定事件ReactEventListener.dispatchEvent會(huì)對(duì)事件進(jìn)行分發(fā),根據(jù)之前存儲(chǔ)的類型(type)和組件標(biāo)識(shí)(_rootNodeID)找到觸發(fā)事件的組件。ReactEventEmitter利用EventPluginHub中注入(inject)的plugins(例如:SimpleEventPlugin、EnterLeaveEventPlugin)會(huì)將原生的DOM事件轉(zhuǎn)化成合成的事件,然后批量執(zhí)行存儲(chǔ)的回調(diào)函,回調(diào)函數(shù)的執(zhí)行分為兩步,第一步是將所有的合成事件放到事件隊(duì)列里面,第二步是逐個(gè)執(zhí)行。需要注意的是,瀏覽器原生會(huì)為每個(gè)事件的每個(gè)listener創(chuàng)建一個(gè)事件對(duì)象,可以從這個(gè)事件對(duì)象獲取到事件的引用。這會(huì)造成高額的內(nèi)存分配,React在啟動(dòng)時(shí)就會(huì)為每種對(duì)象分配內(nèi)存池,用到某一個(gè)事件對(duì)象時(shí)就可以從這個(gè)內(nèi)存池進(jìn)行復(fù)用,節(jié)省內(nèi)存。

  再回到我們剛開始的問題,現(xiàn)在看起來就很沒有很費(fèi)解了,之所以會(huì)出現(xiàn)上面的問題是因?yàn)槲覀兓煊昧薘eact的事件機(jī)制和DOM原生的事件機(jī)制,認(rèn)為通過:

handleClickQr(e) {
    e.stopPropagation();
}

就能阻止原生的事件傳播,其實(shí)在事件委托的情形下是不能實(shí)現(xiàn)這一點(diǎn)的。當(dāng)然解決的辦法也不復(fù)雜,不要將React事件和DOM原生事件混用。

componentDidMount() {
  document.body.addEventListener("click", e => {
    this.setState({
      active: false,
    });
  });
 
  document.querySelector(".code").addEventListener("click", e => {
    e.stopPropagation();
  })
}

componentWillUnmount() {
  document.body.removeEventListener("click");
  document.querySelector(".qr").removeEventListener("click");
}

或者通過事件原件對(duì)象中的target進(jìn)行判斷:

componentDidMount() {
  document.body.addEventListener("click", e => {
    if (e.target && e.target.matches("div.code")) {
      return;
    }
 
    this.setState({
      active: false,
    });
  });
}

都可以解決異常關(guān)閉的問題。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/82126.html

相關(guān)文章

  • 談?wù)?em>React事件機(jī)制和未來(react-events)

    摘要:另外第三方也可以通過的事件插件機(jī)制來合成自定義事件,盡管很少人這么做。抽象跨平臺(tái)事件機(jī)制。打算干預(yù)事件的分發(fā)。事件是的一個(gè)自定義事件,旨在規(guī)范化表單元素的變動(dòng)事件。 showImg(https://segmentfault.com/img/remote/1460000019961124?w=713&h=307); 當(dāng)我們?cè)诮M件上設(shè)置事件處理器時(shí),React并不會(huì)在該DOM元素上直接綁定...

    TNFE 評(píng)論0 收藏0
  • React深入】React事件機(jī)制

    摘要:給注冊(cè)原生事件回調(diào)為統(tǒng)一的事件分發(fā)機(jī)制。根據(jù)元素唯一標(biāo)識(shí)和事件類型從中取出回調(diào)函數(shù)返回帶有合成事件參數(shù)的回調(diào)函數(shù)總流程將上面的四個(gè)流程串聯(lián)起來??梢?,回調(diào)函數(shù)是直接調(diào)用調(diào)用的,并沒有指定調(diào)用的組件,所以不進(jìn)行手動(dòng)綁定的情況下直接獲取到的是。 關(guān)于React事件的疑問 1.為什么要手動(dòng)綁定this 2.React事件和原生事件有什么區(qū)別 3.React事件和原生事件的執(zhí)行順序,可以混...

    philadelphia 評(píng)論0 收藏0
  • 結(jié)合源碼徹底理解 react事件機(jī)制原理 01 - 對(duì)事件機(jī)制的初步理解和驗(yàn)證

    摘要:前言這是事件機(jī)制的第一篇,主要內(nèi)容有表象理解,驗(yàn)證,意義和思考。因?yàn)楹铣墒录挠|發(fā)是基于瀏覽器的事件機(jī)制來實(shí)現(xiàn)的,通過冒泡機(jī)制冒泡到最頂層元素,然后再由統(tǒng)一去處理。合成事件的阻止冒泡不會(huì)影響原生事件。 showImg(https://segmentfault.com/img/bVbtvP2?w=800&h=420); 前言 這是 react 事件機(jī)制的第一篇,主要內(nèi)容有:表象理解,驗(yàn)證...

    muddyway 評(píng)論0 收藏0
  • 淺談React事件機(jī)制

    摘要:事件簡介事件是合成事件,所有事件都自動(dòng)綁定到最外層上。支持事件的冒泡機(jī)制,我們可以使用和來中斷它。這樣做簡化了事件處理和回收機(jī)制,效率也有很大提升。事件類型合成事件的事件類型是原生事件類型的一個(gè)子集。 React事件簡介 React事件是合成事件,所有事件都自動(dòng)綁定到最外層上。因?yàn)閂irtual DOM 在內(nèi)存中是以對(duì)象的形式存在的,所以React 基于 Virtual DOM 實(shí)現(xiàn)了...

    moven_j 評(píng)論0 收藏0
  • 淺談React事件機(jī)制

    摘要:事件簡介事件是合成事件,所有事件都自動(dòng)綁定到最外層上。支持事件的冒泡機(jī)制,我們可以使用和來中斷它。這樣做簡化了事件處理和回收機(jī)制,效率也有很大提升。事件類型合成事件的事件類型是原生事件類型的一個(gè)子集。 React事件簡介 React事件是合成事件,所有事件都自動(dòng)綁定到最外層上。因?yàn)閂irtual DOM 在內(nèi)存中是以對(duì)象的形式存在的,所以React 基于 Virtual DOM 實(shí)現(xiàn)了...

    MyFaith 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<