React合成事件詳解
react合成事件指的是react用js模擬瞭一個Dom事件流。(fiber樹模擬Dom樹結構) 合成事件的事件流在fiber樹中發生捕獲和冒泡。
從點擊輸入框開始
當你點擊input輸入框,react在根節點(註1)監聽到focus事件(註2)(註3)。
如何從原生事件找到對應的虛擬Dom?
此時,react得到的信息隻有原生事件對象(nativeEvent)。react通過nativeEvent對應的Dom(eventTarget),沿著Dom樹向上找到距離該eventTarget最近的被react管理的Dom節點(註4)(註5),並獲得對應的fiber A。
接著通過事件插件(註6),創建合成事件(註7)A。合成事件A被react視為模擬事件流中的事件源,fiber A被react視為事件目標。
合成事件流?
從fiber A出發向上(直到頂層fiber HostComponent為止)收集所有的host類型的fiber。 然後將收集到的fiber數組,從後向前(捕獲),再從前向後(冒泡)遍歷。每次遍歷,會收集(註8)當前遍歷項fiber節點的綁定的focus事件。之後(事件插件完成後,即合成事件生成好瞭)會按照收集的順序執行foucs回調。 react就是這樣模擬瞭事件流。
擴展
點擊輸入框引起多個事件
除瞭focus外,也觸發瞭其他的事件–click等。react在根節點對不同類型的事件進行瞭監聽,每監聽到一種事件就會派發一次,多種類型的事件,會派發多次。 點擊輸入框,會先後觸發focus和click。當focus事件的派發完後,就會派發click事件。 每次某個事件派發結束,會處理待處理的同步任務隊列(flushSyncCallBackQueue)。
意料之外的render?
在NoMode模式下,多次派發事件且每個事件都改變瞭狀態(如調用setState),則對應組件會被render多次。 在本例中,點擊input輸入框,如果給input綁定瞭focus事件和click事件並且事件回調都調用setState,input將會render兩次。
為什麼react中的input設置value後成為受控組件?
react中,在input設置瞭value屬性的條件下,無論在輸入框中輸入什麼,輸入框的值都不會改變。除非你改變瞭input組件的state。 react在處理完模擬事件流後,會調用方法將一些意外的效果重置。 例如該場景,在input中輸入瞭一個值,input輸入框會出現你輸入的值,但馬上input的值會被對應的fiber的value屬性更新(finishEventHander 重置受控組件)。 如果沒有給input設置value則會忽略。
為什麼合成事件屬性有時無法訪問?
因為react在事件流(捕獲到冒泡)完後就將合成事件對象釋放(SyntheticEvent.prototype.destructor 將合成事件對象的屬性重置)。
react如何模擬事件的阻止冒泡、阻止默認行為?
react按照事件流順序執行回調,在執行前會檢查當前合成事件對象是否處於阻止冒泡的狀態,如果是,則終止事件流。 react的合成事件對象原型對原生函數進行增強。對原生事件方法的阻止冒泡、阻止默認行為進行瞭封裝(內部也調用原生事件的方法)。
註釋
註1:根節點,在 react-v16 為 document ,在 react-v17 為掛載容器Dom
註2:focus事件並不是冒泡事件,react對非冒泡事件在捕獲階段監聽
註3:根節點對所有事件進行瞭監聽,除瞭特別例外submit、reset、invalid和媒體事件等
註4:react將fiber樹掛載到Dom樹上時,每個宿主(host)類型fiber節點與Dom節點一一對應,並鏈接
註5:向上查找是因為可能子Dom節點並不是被react管理的,如第三庫滾動插件等
註6:為瞭模擬Dom事件,react進行的補充
註7:react內部一個構造函數的實例,合成事件的部分屬性來源於nativeEvent。合成事件與fiber關聯
註8:收集而不是執行。因為react針對某一類型事件的做瞭批處理
以上就是React合成事件詳解的詳細內容,更多關於React合成事件的資料請關註WalkonNet其它相關文章!
推薦閱讀:
- react合成事件與原生事件的相關理解
- React的diff算法核心復用圖文詳解
- React setState是異步還是同步原理解析
- 深入分析React源碼中的合成事件
- 深入理解React State 原理