国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

談談React事件機制和未來(react-events)

TNFE / 3402人閱讀

摘要:另外第三方也可以通過的事件插件機制來合成自定義事件,盡管很少人這么做。抽象跨平臺事件機制。打算干預事件的分發。事件是的一個自定義事件,旨在規范化表單元素的變動事件。

當我們在組件上設置事件處理器時,React并不會在該DOM元素上直接綁定事件處理器. React內部自定義了一套事件系統,在這個系統上統一進行事件訂閱和分發.

具體來講,React利用事件委托機制在Document上統一監聽DOM事件,再根據觸發的target將事件分發到具體的組件實例。另外上面e是一個合成事件對象(SyntheticEvent), 而不是原始的DOM事件對象.

文章大綱

那為什么要自定義一套事件系統?

基本概念

整體的架構

事件分類與優先級

實現細節

事件是如何綁定的?

事件是如何分發的?

事件觸發調度

插件是如何處理事件?

批量執行

未來

初探Responder的創建

react-events意義何在?

擴展閱讀

截止本文寫作時,React版本是16.8.6
那為什么要自定義一套事件系統?

如果了解過Preact(筆者之前寫過一篇文章解析Preact的源碼),Preact裁剪了很多React的東西,其中包括事件機制,Preact是直接在DOM元素上進行事件綁定的。

在研究一個事物之前,我首先要問為什么?了解它的動機,才有利于你對它有本質的認識。

React自定義一套事件系統的動機有以下幾個:

1. 抹平瀏覽器之間的兼容性差異。 這是估計最原始的動機,React根據W3C 規范來定義這些合成事件(SyntheticEvent), 意在抹平瀏覽器之間的差異。

另外React還會試圖通過其他相關事件來模擬一些低版本不兼容的事件, 這才是‘合成’的本來意思吧?。

2. 事件‘合成’, 即事件自定義。事件合成除了處理兼容性問題,還可以用來自定義高級事件,比較典型的是React的onChange事件,它為表單元素定義了統一的值變動事件。另外第三方也可以通過React的事件插件機制來合成自定義事件,盡管很少人這么做。

3. 抽象跨平臺事件機制。 和VirtualDOM的意義差不多,VirtualDOM抽象了跨平臺的渲染方式,那么對應的SyntheticEvent目的也是想提供一個抽象的跨平臺事件機制。

4. React打算做更多優化。比如利用事件委托機制,大部分事件最終綁定到了Document,而不是DOM節點本身. 這樣簡化了DOM事件處理邏輯,減少了內存開銷. 但這也意味著,React需要自己模擬一套事件冒泡的機制

5. React打算干預事件的分發。v16引入Fiber架構,React為了優化用戶的交互體驗,會干預事件的分發。不同類型的事件有不同的優先級,比如高優先級的事件可以中斷渲染,讓用戶代碼可以及時響應用戶交互。

Ok, 后面我們會深入了解React的事件實現,我會盡量不貼代碼,用流程圖說話。

基本概念 整體的架構

ReactEventListener - 事件處理器. 在這里進行事件處理器的綁定。當DOM觸發事件時,會從這里開始調度分發到React組件樹

ReactEventEmitter - 暴露接口給React組件層用于添加事件訂閱

EventPluginHub - 如其名,這是一個‘插件插槽’,負責管理和注冊各種插件。在事件分發時,調用插件來生成合成事件

Plugin - React事件系統使用了插件機制來管理不同行為的事件。這些插件會處理自己感興趣的事件類型,并生成合成事件對象。目前ReactDOM有以下幾種插件類型:

SimpleEventPlugin - 簡單事件, 處理一些比較通用的事件類型,例如click、input、keyDown、mouseOver、mouseOut、pointerOver、pointerOut

EnterLeaveEventPlugin - mouseEnter/mouseLeave和pointerEnter/pointerLeave這兩類事件比較特殊, 和*over/*leave事件相比, 它們不支持事件冒泡, *enter會給所有進入的元素發送事件, 行為有點類似于:hover; 而*over在進入元素后,還會冒泡通知其上級. 可以通過這個實例觀察enter和over的區別.

如果樹層次比較深,大量的mouseenter觸發可能導致性能問題。另外其不支持冒泡,無法在Document完美的監聽和分發, 所以ReactDOM使用*over/*out事件來模擬這些*enter/*leave

ChangeEventPlugin - change事件是React的一個自定義事件,旨在規范化表單元素的變動事件。

它支持這些表單元素: input, textarea, select

SelectEventPlugin - 和change事件一樣,React為表單元素規范化了select(選擇范圍變動)事件,適用于input、textarea、contentEditable元素.

BeforeInputEventPlugin - beforeinput事件以及composition事件處理。

本文主要會關注SimpleEventPlugin的實現,有興趣的讀者可以自己閱讀React的源代碼.

EventPropagators 按照DOM事件傳播的兩個階段,遍歷React組件樹,并收集所有組件的事件處理器.

EventBatching 負責批量執行事件隊列和事件處理器,處理事件冒泡。

SyntheticEvent 這是‘合成’事件的基類,可以對應DOM的Event對象。只不過React為了減低內存損耗和垃圾回收,使用一個對象池來構建和釋放事件對象, 也就是說SyntheticEvent不能用于異步引用,它在同步執行完事件處理器后就會被釋放。

SyntheticEvent也有子類,和DOM具體事件類型一一匹配:

SyntheticAnimationEvent

SyntheticClipboardEvent

SyntheticCompositionEvent

SyntheticDragEvent

SyntheticFocusEvent

SyntheticInputEvent

SyntheticKeyboardEvent

SyntheticMouseEvent

SyntheticPointerEvent

SyntheticTouchEvent

....

事件分類與優先級

SimpleEventPlugin將事件類型劃分成了三類, 對應不同的優先級(優先級由低到高):

DiscreteEvent 離散事件. 例如blur、focus、 click、 submit、 touchStart. 這些事件都是離散觸發的

UserBlockingEvent 用戶阻塞事件. 例如touchMove、mouseMove、scroll、drag、dragOver等等。這些事件會"阻塞"用戶的交互。

ContinuousEvent 可連續事件。例如load、error、loadStart、abort、animationEnd. 這個優先級最高,也就是說它們應該是立即同步執行的,這就是Continuous的意義,即可連續的執行,不被打斷.

可能要先了解一下React調度(Schedule)的優先級,才能理解這三種事件類型的區別。截止到本文寫作時,React有5個優先級級別:

Immediate - 這個優先級的任務會同步執行, 或者說要馬上執行且不能中斷

UserBlocking(250ms timeout) 這些任務一般是用戶交互的結果, 需要即時得到反饋 .

Normal (5s timeout) 應對哪些不需要立即感受到的任務,例如網絡請求

Low (10s timeout) 這些任務可以放后,但是最終應該得到執行. 例如分析通知

Idle (no timeout) 一些沒有必要做的任務 (e.g. 比如隱藏的內容).

目前ContinuousEvent對應的是Immediate優先級; UserBlockingEvent對應的是UserBlocking(需要手動開啟); 而DiscreteEvent對應的也是UserBlocking, 只不過它在執行之前,先會執行完其他Discrete任務。

本文不會深入React Fiber架構的細節,有興趣的讀者可以閱讀文末的擴展閱讀列表.

實現細節

現在開始進入文章正題,React是怎么實現事件機制?主要分為兩個部分: 綁定分發.

事件是如何綁定的?

為了避免后面繞暈了,有必要先了解一下React事件機制中的插件協議。 每個插件的結構如下:

export type EventTypes = {[key: string]: DispatchConfig};

// 插件接口
export type PluginModule = {
  eventTypes: EventTypes,          // 聲明插件支持的事件類型
  extractEvents: (                 // 對事件進行處理,并返回合成事件對象
    topLevelType: TopLevelType,
    targetInst: null | Fiber,
    nativeEvent: NativeEvent,
    nativeEventTarget: EventTarget,
  ) => ?ReactSyntheticEvent,
  tapMoveThreshold?: number,
};

eventTypes聲明該插件負責的事件類型, 它通過DispatchConfig來描述:

export type DispatchConfig = {
  dependencies: Array, // 依賴的原生事件,表示關聯這些事件的觸發. ‘簡單事件’一般只有一個,復雜事件如onChange會監聽多個, 如下圖           
               
                                           
                       
                 

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/106354.html

相關文章

  • 一個播放器引發的思考——談談React跨組件通信

    摘要:如果某個組件訂閱該事件太晚,那發布者之前所發布的該類事件,它都接收不到,而方案一和二的優點則在于,無論如何,組件都能拿到該的最終狀態值有存在內存泄漏的風險。 原文地址 - 歡迎關注我的博客 在我們react項目日常開發中,往往會遇到這樣一個問題:如何去實現跨組件通信? 為了更好的理解此問題,接下來我們通過一個簡單的栗子說明。 實現一個視頻播放器 假設有一個這樣的需求,需要我們去實現一個...

    Dean 評論0 收藏0
  • 一個播放器引發的思考——談談React跨組件通信

    摘要:如果某個組件訂閱該事件太晚,那發布者之前所發布的該類事件,它都接收不到,而方案一和二的優點則在于,無論如何,組件都能拿到該的最終狀態值有存在內存泄漏的風險。 原文地址 - 歡迎關注我的博客 在我們react項目日常開發中,往往會遇到這樣一個問題:如何去實現跨組件通信? 為了更好的理解此問題,接下來我們通過一個簡單的栗子說明。 實現一個視頻播放器 假設有一個這樣的需求,需要我們去實現一個...

    zhongmeizhi 評論0 收藏0
  • 談談React中Diff算法的策略及實現

    摘要:并且處理特殊屬性,比如事件綁定。之后根據差異對象操作元素位置變動,刪除,添加等。當節點數過大或者頁面更新次數過多時,頁面卡頓的現象會比較明顯。基于注意使用來減少組件不必要的更新。 1、什么是Diff算法 傳統Diff:diff算法即差異查找算法;對于Html DOM結構即為tree的差異查找算法;而對于計算兩顆樹的差異時間復雜度為O(n^3),顯然成本太高,React不可能采用這種...

    Scliang 評論0 收藏0
  • 談談React中Diff算法的策略及實現

    摘要:并且處理特殊屬性,比如事件綁定。之后根據差異對象操作元素位置變動,刪除,添加等。當節點數過大或者頁面更新次數過多時,頁面卡頓的現象會比較明顯。基于注意使用來減少組件不必要的更新。 1、什么是Diff算法 傳統Diff:diff算法即差異查找算法;對于Html DOM結構即為tree的差異查找算法;而對于計算兩顆樹的差異時間復雜度為O(n^3),顯然成本太高,React不可能采用這種...

    HmyBmny 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<