摘要:給注冊原生事件回調為統一的事件分發機制。根據元素唯一標識和事件類型從中取出回調函數返回帶有合成事件參數的回調函數總流程將上面的四個流程串聯起來??梢?,回調函數是直接調用調用的,并沒有指定調用的組件,所以不進行手動綁定的情況下直接獲取到的是。
關于React事件的疑問
1.為什么要手動綁定this
2.React事件和原生事件有什么區別
3.React事件和原生事件的執行順序,可以混用嗎
4.React事件如何解決跨瀏覽器兼容
5.什么是合成事件
下面是我閱讀過源碼后,將所有的執行流程總結出來的流程圖,不會貼代碼,如果你想閱讀代碼看看具體是如何實現的,可以根據流程圖去源碼里尋找。
事件注冊組件裝載 / 更新。
通過lastProps、nextProps判斷是否新增、刪除事件分別調用事件注冊、卸載方法。
調用EventPluginHub的enqueuePutListener進行事件存儲
獲取document對象。
根據事件名稱(如onClick、onCaptureClick)判斷是進行冒泡還是捕獲。
判斷是否存在addEventListener方法,否則使用attachEvent(兼容IE)。
給document注冊原生事件回調為dispatchEvent(統一的事件分發機制)。
事件存儲EventPluginHub負責管理React合成事件的callback,它將callback存儲在listenerBank中,另外還存儲了負責合成事件的Plugin。
EventPluginHub的putListener方法是向存儲容器中增加一個listener。
獲取綁定事件的元素的唯一標識key。
將callback根據事件類型,元素的唯一標識key存儲在listenerBank中。
listenerBank的結構是:listenerBank[registrationName][key]。
例如:
{ onClick:{ nodeid1:()=>{...} nodeid2:()=>{...} }, onChange:{ nodeid3:()=>{...} nodeid4:()=>{...} } }事件觸發 / 執行
這里的事件執行利用了React的批處理機制,在前一篇的【React深入】setState執行機制中已經分析過,這里不再多加分析。
觸發document注冊原生事件的回調dispatchEvent
獲取到觸發這個事件最深一級的元素
例如下面的代碼:首先會獲取到this.child
this.parent = ref}>this.child = ref}> test
遍歷這個元素的所有父元素,依次對每一級元素進行處理。
構造合成事件。
將每一級的合成事件存儲在eventQueue事件隊列中。
遍歷eventQueue。
通過isPropagationStopped判斷當前事件是否執行了阻止冒泡方法。
如果阻止了冒泡,停止遍歷,否則通過executeDispatch執行合成事件。
釋放處理完成的事件。
react在自己的合成事件中重寫了stopPropagation方法,將isPropagationStopped設置為true,然后在遍歷每一級事件的過程中根據此遍歷判斷是否繼續執行。這就是react自己實現的冒泡機制。
合成事件調用EventPluginHub的extractEvents方法。
循環所有類型的EventPlugin(用來處理不同事件的工具方法)。
在每個EventPlugin中根據不同的事件類型,返回不同的事件池。
在事件池中取出合成事件,如果事件池是空的,那么創建一個新的。
根據元素nodeid(唯一標識key)和事件類型從listenerBink中取出回調函數
返回帶有合成事件參數的回調函數
總流程將上面的四個流程串聯起來。
為什么要手動綁定this通過事件觸發過程的分析,dispatchEvent調用了invokeGuardedCallback方法。
function invokeGuardedCallback(name, func, a) { try { func(a); } catch (x) { if (caughtError === null) { caughtError = x; } } }
可見,回調函數是直接調用調用的,并沒有指定調用的組件,所以不進行手動綁定的情況下直接獲取到的this是undefined。
這里可以使用實驗性的屬性初始化語法 ,也就是直接在組件聲明箭頭函數。箭頭函數不會創建自己的this,它只會從自己的作用域鏈的上一層繼承this。因此這樣我們在React事件中獲取到的就是組件本身了。
和原生事件有什么區別React 事件使用駝峰命名,而不是全部小寫。
通過 JSX , 你傳遞一個函數作為事件處理程序,而不是一個字符串。
例如,HTML:
在 React 中略有不同:
另一個區別是,在 React 中你不能通過返回 false 來阻止默認行為。必須明確調用 preventDefault 。
由上面執行機制我們可以得出:React自己實現了一套事件機制,自己模擬了事件冒泡和捕獲的過程,采用了事件代理,批量更新等方法,并且抹平了各個瀏覽器的兼容性問題。
React事件和原生事件的執行順序componentDidMount() { this.parent.addEventListener("click", (e) => { console.log("dom parent"); }) this.child.addEventListener("click", (e) => { console.log("dom child"); }) document.addEventListener("click", (e) => { console.log("document"); }) } childClick = (e) => { console.log("react child"); } parentClick = (e) => { console.log("react parent"); } render() { return (this.parent = ref}>) }this.child = ref}> test
執行結果:
由上面的流程我們可以理解:
react的所有事件都掛載在document中
當真實dom觸發后冒泡到document后才會對react事件進行處理
所以原生的事件會先執行
然后執行react合成事件
最后執行真正在document上掛載的事件
react事件和原生事件可以混用嗎?react事件和原生事件最好不要混用。
原生事件中如果執行了stopPropagation方法,則會導致其他react事件失效。因為所有元素的事件將無法冒泡到document上。
由上面的執行機制不難得出,所有的react事件都將無法被注冊。
合成事件、瀏覽器兼容function handleClick(e) { e.preventDefault(); console.log("The link was clicked."); }
這里, e 是一個合成的事件。 React 根據 W3C 規范 定義了這個合成事件,所以你不需要擔心跨瀏覽器的兼容性問題。
事件處理程序將傳遞 SyntheticEvent 的實例,這是一個跨瀏覽器原生事件包裝器。 它具有與瀏覽器原生事件相同的接口,包括 stopPropagation() 和 preventDefault() ,在所有瀏覽器中他們工作方式都相同。
每個 SyntheticEvent 對象都具有以下屬性:
boolean bubbles boolean cancelable DOMEventTarget currentTarget boolean defaultPrevented number eventPhase boolean isTrusted DOMEvent nativeEvent void preventDefault() boolean isDefaultPrevented() void stopPropagation() boolean isPropagationStopped() DOMEventTarget target number timeStamp string type
React合成的SyntheticEvent采用了事件池,這樣做可以大大節省內存,而不會頻繁的創建和銷毀事件對象。
另外,不管在什么瀏覽器環境下,瀏覽器會將該事件類型統一創建為合成事件,從而達到了瀏覽器兼容的目的。
推薦閱讀【React深入】setState的執行機制
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/102379.html
摘要:以我自己的理解,函數式編程就是以函數為中心,將大段過程拆成一個個函數,組合嵌套使用。越來越多的跡象表明,函數式編程已經不再是學術界的最愛,開始大踏步地在業界投入實用。也許繼面向對象編程之后,函數式編程會成為下一個編程的主流范式。 使用React也滿一年了,從剛剛會使用到逐漸探究其底層實現,以便學習幾招奇技淫巧從而在自己的代碼中使用,寫出高效的代碼。下面整理一些知識點,算是React看書...
摘要:另外第三方也可以通過的事件插件機制來合成自定義事件,盡管很少人這么做。抽象跨平臺事件機制。打算干預事件的分發。事件是的一個自定義事件,旨在規范化表單元素的變動事件。 showImg(https://segmentfault.com/img/remote/1460000019961124?w=713&h=307); 當我們在組件上設置事件處理器時,React并不會在該DOM元素上直接綁定...
摘要:調用事務的方法,遍歷待更新組件隊列依次執行更新。執行生命周期,根據返回值判斷是否要繼續更新。三總結鉤子函數和合成事件中在的生命周期和合成事件中,仍然處于他的更新機制中,這時為。這時將執行之前累積的。 一.幾個開發中經常會遇到的問題 以下幾個問題是我們在實際開發中經常會遇到的場景,下面用幾個簡單的示例代碼來還原一下。 1.setState是同步還是異步的,為什么有的時候不能立即拿到更新結...
摘要:前言接下來讓我們進入新的章節漫談。正文一事件系統的事件系統事件系統符合標準,不存在任何兼容性問題,并且與原生的瀏覽器事件一樣有同樣的接口。所有的事件都自動綁定到最外層。組織事件冒泡的行為只適用于合成系統中,且沒辦法阻止原生事件冒泡。 前言 接下來讓我們進入新的章節:漫談React。本篇文章主要講React事件系統和表單操作。 正文 一:事件系統 1.react的事件系統react事件系...
閱讀 3095·2021-10-13 09:40
閱讀 3945·2021-09-22 15:51
閱讀 1493·2021-09-22 15:48
閱讀 1060·2021-09-06 15:00
閱讀 1790·2019-08-30 15:43
閱讀 2356·2019-08-29 18:35
閱讀 1667·2019-08-29 16:18
閱讀 3612·2019-08-29 12:49