歡迎訂閱React技術揭祕react
當提出這個問題時,個人第一反應是——我還真是無聊 🤷♂️git
轉念一想,em~,好像事情沒有這麼簡單🤔github
若是直接選擇全部div
再遍歷刪除的話,div
的子孫節點也被刪除了。有什麼辦法能在保留整棵DOM樹層級關係的前提下,只刪除div
節點呢?面試
我陷入了沉思。。。。。chrome
知乎是React寫的,React用JSX來表示頁面層次結構,JSX在編譯時會被babel轉換爲React.createElement
。瀏覽器
在代碼運行時,React獲取的實際上是React.createElement()
的返回值。babel
辦法來了!markdown
咱們只須要覆寫一下React.createElement
方法,當遇到type === 'div'
,咱們將type
修改成React.Fragment
,即咱們把全部div
節點都變成Fragment
,那不就能在保持樹的層級關係的同時去掉div
了?ide
讓咱們開始吧!!函數
這時候遇到了第一個問題:知乎沒把React暴露到全局(廢話,固然不會😠),怎麼獲取React對象呢?
好在當咱們使用React Dev Tools
時,Dev Tools
會向頁面注入全局變量__REACT_DEVTOOLS_GLOBAL_HOOK__
,這個變量會成爲連接React
與Dev Tools
的橋樑。
其中的renderers
屬性指頁面使用的渲染器,在網頁端就是咱們熟悉的React-DOM
(在客戶端固然就是React-Native
啦)
咱們發現一個方法findFiberByHostInstance
方法名竟然出現了Fiber
字樣!!
咱們知道,Fiber
是React的最小可調度單元(別問爲何,問就是安利我寫的React技術揭祕)
那findFiberByHostInstance
方法所在文件必定有React相關定義。咱們右鍵跳轉到定義函數的文件,
在文件內搜.createElement
果真讓咱們找到了。打上斷點,刷新頁面試試~
果真進來了,事情愈加有趣了 😊😊😊
看看o.a
是什麼,em~~一個對象,內部有Children
、createElement
。。。。。。
看來這就是React對象了
趕緊把來之不易的React對象保存在全局,順便把React.createElement也保存一份。
如今放開斷點,window.React
已經指向知乎首頁內部使用的React啦。
咱們知道,React.createElement方法第一個參數爲type
(別問爲何,問又是一波安利React技術揭祕),咱們再到React文檔中找來React.Fragment
的定義。
if (typeof Symbol === 'function' && Symbol.for) { const symbolFor = Symbol.for; REACT_ELEMENT_TYPE = symbolFor('react.element'); REACT_PORTAL_TYPE = symbolFor('react.portal'); REACT_FRAGMENT_TYPE = symbolFor('react.fragment'); REACT_STRICT_MODE_TYPE = symbolFor('react.strict_mode'); REACT_PROFILER_TYPE = symbolFor('react.profiler'); REACT_PROVIDER_TYPE = symbolFor('react.provider'); // ... } 複製代碼
接下來,修改全局變量
React.createElement = (type, ...args) => { if (type === 'div') { type = Symbol.for('react.fragment'); } // originCreateElement纔是正經的React.createElement return originCreateElement(type, ...args); } 複製代碼
讓咱們康康此時的頁面結構
ok~~~ 滿屏的div套div(嫌棄臉),接着咱們輕輕的點一下關注按鈕,觸發隨便啥組件的setState
。
接下來,就是見證奇蹟的時刻。。。
除了根節點,其餘div
都消失啦,終於恢復了往日的清爽界面(大誤)
經過這篇無聊的文章,咱們認識到:
setState
更新,都會從新遍歷整棵Fiber樹。(不然也不會點擊一個按鈕整個頁面的div
都消失)div
了PS:若是你用Chrome將被壓縮後的代碼formatted
後打上斷點,刷新頁面進入斷點後瀏覽器卡死,不要懷疑,這是Chrome的bug,截止版本 81.0.4044.138(正式版本) (64 位)
還未修復,建議使用chrome開發者版本 Chrome Canary