窺探react事件

寫在前面

本文源於本人在學習react過程當中遇到的一個問題;本文內容爲本人的一些的理解,若有不對的地方,還請你們指出來。本文是講react的事件,不是介紹其api,而是猜測一下react合成事件的實現方式react

遇到的問題

class EventTest extends Component {
    handleParentClick(e) {
        console.log('click parent div');
    }
    handleChildClick(e) {
        e.stopPropagation();
        console.log('click child div');
    }
    componentDidMount() {
        document.querySelector('.parent').addEventListener('click', this.handleParentClick);
    }
    render() {
        return (
            <div className="parent">
                <div className="child" onClick={this.handleChildClick}></div>
            </div>
        );
    }
}

上述代碼render出來後,嘗試點擊一下div.child,詭異的現象產生了:web

clipboard.png

控制檯中輸出如上圖所示,這徹底不符合瀏覽器的事件執行啊,我所指望的是指輸出click child div,由於已經利用了e.stopPropagation()來阻止冒泡,說明阻止冒泡失效了,可是僅僅如此嗎,能夠發現的是首先輸出的是click parent div(wtf)。chrome

解決問題

爲了解決上述問題,先來了解下react的事件,react事件是合成事件,爲原生事件的一個子集,僅僅是進行了一個跨瀏覽器的封裝。可是真的只有這麼簡單?圖樣圖森破。
利用控制檯,看下div.child對應的事件處理函數:api

clipboard.png

一個空函數,事件的監聽函數不是所定義的handleChildClick,而是emptyFunction,也就是說react沒有在真實的DOM節點上綁定事件(在DOM節點上綁定事件比較消耗內存,由於當dom節點被remove後,雖然不存在與dom tree中,可是仍存在與內存中,須要手動remove事件orchild = null),react的合成事件利用的是事件代理方式實現,也就是說會將事件監聽器綁定到整個文檔document上,是否是這樣呢?來驗證一下,利用chrome:瀏覽器

clipboard.png

能夠發現,document上的確被綁定了click事件,dom節點的真實的事件處理函數所有以一個特定的結構存儲在了內存中,當點擊div.child時,這時其事件處理函數爲emptyFunction,執行這個函數無任何做用,按照瀏覽器標準事件模型,開始向上冒泡,這時到了div.parent,因而輸出了click parent div,一直向上到了document,這時根據e.target進行處理,而react並不會根據dom層級式傳播那樣遍歷virtual dom結構,這樣有時遍歷的層級會不少,並且會有不少的無效遍歷。dom

react是怎麼作的呢?

react依靠每一個React component各自獨立的id來編碼這個層級。這樣就能經過簡單的字符串操做來獲取全部父級 component 的父級內容,再把事件監聽存儲在hashmap當中,好比有以下結構而且爲沒一層div添加onClick函數

div.a
    div.b
        div.c

當點擊div.c時,處理方式:學習

clickBubbleListeners['a.b.c'](event);
clickBubbleListeners['a.b'](event);
clickBubbleListeners['a'](event);

在合成事件中用e.stopPropagation只能阻斷上述冒泡過程。this

結論

由此能夠看出:編碼

  • 阻止react事件冒泡的行爲只能用於react合成事件中,對於原生事件無效(合成事件中的e.stopPropagation與原生事件中的e.stopPropagation並非一回事)

  • 阻止原生事件的冒泡行爲,能夠阻止react合成事件的傳播(根本不會冒泡到document上,因此不會觸發react的合成事件)

  • 在寫react時,最好不要將合成事件與原生事件混用

參考

本文部分參考自IMWeb—React事件初探

相關文章
相關標籤/搜索