React源碼解析18(8)------ 實現單節點的Diff算法

摘要

經過之前的幾篇文章,我們已經實現了一個可以進行更新渲染的假React。但是如果我們把我們的jsx修改成這樣:

function App() {const [age, setAge] = useState(20)const click = function() {setAge(age + 1)}return age % 2 === 0 ? jsx("div", {key: 'div1',children: jsx("span", {key: 'span',children: 'div1',onClick: click})}) : jsx("div", {key: 'div1',children: jsx("span", {key: 'span',children: 'div2',onClick: click})})
}ReactDOM.createRoot(root).render(<App />)

雖然頁面的效果是正確的。但對于兩個jsx,二者的區別僅僅是span標簽里面的內容不同。
但是在程序里面,我們是相當于每次都重新beginWork,重新的創建Filber樹,重新的創建真實DOM。
而對于這里div和span標簽,它沒有任何的改變,我們是否可以用一種優化策略,從而對舊資源進行利用呢? 所以Diff由此而來。

這一篇先只說單節點的Diff,因為目前還沒實現帶有sibling的情況。

1.修改beginWork

我們回顧一下在beginWork里面干了什么。在將jsx轉換為ReactElement后,我們會通過beginWork來構建一顆Filber樹。
那如果,對于可復用的FilberNode,我們是否可以不去創建,直接復用呢?
可以的,那對于React來說,什么節點是可復用的呢:

如果舊的FilberNode和新的ReactElement
key相同,type相同。
那么就是可以復用的。

所以在beginWork中的reconcileChildren方法里,如果我們發現上面的情況,我們就不會創建新的FilberNode。

function reconcileChildren(parent,element) {const newChild = diffReconcileChildren(parent, element);if(newChild) {return newChild}//其他代碼。。。return filberNode
}

2.實現diffReconcileChildren方法

該方法接受兩個參數,第一個是父節點,第二個是新的ReactElement。

(1)我們要先拿到父節點的child,比較child和element的key和type。
(2)將element保存在child的memoizedState里面。
(3)然后其他邏輯和reconcileChildren里的一樣即可。
(4)直接返回child。

function diffReconcileChildren(filberNode, element) {const child = filberNode.child;if(child && child.key && child.type) {if(child.key === element.key && child.type === child.type) {child.memoizedProps = element;child.pendingProps = element.props;if(child.tag === HostText) {child.pendingProps = element}return child;}}
}

這里為什么要將element保存在memoizedState里面,是因為雖然節點沒有改變,但是子節點可能有改變,或者屬性會有改變。所以要在后面的completeWork里進行處理。

3.修改completeWork

經過上面的處理后,FilberNode不會無腦的重復創建,而是復用了。而completeWork的工作,主要是創建真實DOM,掛載在FilberNode的stateNode上。

所以在completeWork中,也不能無腦的創建真實DOM,而是也要判斷是否是可復用的。

export const completeWork = (filberNode) => {const tag = filberNode.tagswitch (tag) {case HostComponent: {if(filberNode.stateNode !== null){//更新updateCompleteHostComponent(filberNode)}else{completeHostComponent(filberNode)}break;}//其他代碼。。。。}
}

所以在對HostComponent的處理上,如果發現不是mount階段,就要判斷是否需要復用舊的。

4.實現updateCompleteHostComponent方法

在該方法中,我們接受filberNode。同時我們可以拿到它的memoizedState(在beginWork中傳過來的)。

再判斷一下key和type,如果依舊相同,那么說明是可復用的。我們直接不創建新的DOM即可。

function updateCompleteHostComponent(filberNode) {const element = filberNode.memoizedProps;if(element.key === filberNode.key && element.type === filberNode.type) {addPropsToDOM(filberNode.stateNode, filberNode.pendingProps)}else{const type = filberNode.type;const element = document.createElement(type);addPropsToDOM(element, filberNode.pendingProps)filberNode.stateNode = element;const parent = filberNode.return;if(parent && parent.stateNode && parent.tag === HostComponent) {parent.stateNode.appendChild(element)}}completeWork(filberNode.child)
}

addPropsToDOM方法是我們在實現事件機制的時候,需要調用的方法。

OK,這樣我們就實現了單節點的Diff算法。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/41492.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/41492.shtml
英文地址,請注明出處:http://en.pswp.cn/news/41492.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

學習紅外成像儀開發注意要點

學習紅外成像儀開發注意要點 三河凡科科技飛訊紅外成像儀開發學習注意要點 紅外成像儀是一種高級的光學設備&#xff0c;可用于探測、分析和顯示紅外輻射&#xff0c;它廣泛應用于醫學、軍事、石油、礦產資源勘探等領域。紅外成像儀的開發需要注意以下幾個方面&#xff1a; 1…

(搜索) 劍指 Offer 12. 矩陣中的路徑 ——【Leetcode每日一題】

?劍指 Offer 12. 矩陣中的路徑 難度&#xff1a;中等 給定一個 m * n 二維字符網格 board 和一個字符串單詞 word 。如果 word 存在于網格中&#xff0c;返回 true &#xff1b;否則&#xff0c;返回 false 。 單詞必須按照字母順序&#xff0c;通過相鄰的單元格內的字母構…

使用Rust編寫的一款使用遺傳算法、神經網絡、WASM技術的模擬生物進化的程序

模擬生物進化程序 Github地址&#xff1a;FishLife 期待各位的star??? 本項目是一個模擬生物進化的程序&#xff0c;利用遺傳算法、神經網絡技術對魚的眼睛和大腦進行模擬。該項目是使用 Rust 語言編寫的&#xff0c;并編譯為 WebAssembly (Wasm) 格式&#xff0c;使其可以…

QT學習方法

1 .類的學習方法 第一步:從UI文件中,找到界面的類—QMainWindow第二步:在Qt Creator工具中,找到“幫助”按鈕,進入到幫助菜單界面,在選擇"索引",在Look for:輸入類名,找到類名,雙擊條目中的類名,在右側會顯示出來類的詳細內容第三步:在右側,可根據內容目錄…

Spring項目使用Redis限制用戶登錄失敗的次數以及暫時鎖定用戶登錄權限

文章目錄 背景環境代碼實現0. 項目結構圖&#xff08;供參考&#xff09;1. 數據庫中的表&#xff08;供參考&#xff09;2. 依賴&#xff08;pom.xml&#xff09;3. 配置文件&#xff08;application.yml&#xff09;4. 配置文件&#xff08;application-dev.yml&#xff09;5…

Camera Link 接口

Camera Link是一個標準的接口協議&#xff0c;用于高速的圖像數據傳輸&#xff0c;常被用在工業相機和圖像處理系統之間。這個標準由自動視覺協會&#xff08;Automated Imaging Association&#xff0c;簡稱AIA&#xff09;在2000年發布&#xff0c;旨在實現各種廠家之間的高性…

在ubuntu+cpolar+rabbitMQ環境下,實現mq服務端遠程訪問

文章目錄 前言1.安裝erlang 語言2.安裝rabbitMQ3. 內網穿透3.1 安裝cpolar內網穿透(支持一鍵自動安裝腳本)3.2 創建HTTP隧道 4. 公網遠程連接5.固定公網TCP地址5.1 保留一個固定的公網TCP端口地址5.2 配置固定公網TCP端口地址 前言 RabbitMQ是一個在 AMQP(高級消息隊列協議)基…

使用opencv4.7.0部署yolov5

yolov5原理和部署原理就不說了&#xff0c;想了解的可以看看這篇部署原理文章 #include <fstream> #include <sstream> #include <iostream> #include <opencv2/dnn.hpp> #include <opencv2/imgproc.hpp> #include <opencv2/highgui.hpp>/…

【Java轉Go】快速上手學習筆記(二)之基礎篇一

目錄 創建項目數據類型變量常量類型轉換計數器鍵盤交互流程控制代碼運算符 創建項目 上篇我們安裝好了Go環境&#xff0c;和用IDEA安裝Go插件來開發Go項目&#xff1a;【Java轉Go】快速上手學習筆記&#xff08;一&#xff09;之環境安裝篇 。 這篇我們開始正式學習Go語言。我…

MyBatis動態SQL:打造靈活可變的數據庫操作

目錄 if標簽trim標簽where標簽set標簽foreach標簽 動態SQL就是根據不同的條件或需求動態地生成查詢語句&#xff0c;比如動態搜索條件、動態表或列名、動態排序等。 if標簽 在我們填寫一些信息時&#xff0c;有些信息是必填字段&#xff0c;有的則是非必填的&#xff0c;這些…

淘寶API接口的實時數據和緩存數據區別

電商API接口實時數據是指通過API接口獲取到的與電商相關的實時數據。這些數據可以包括商品庫存、訂單狀態、銷售額、用戶活躍度等信息。 通過電商API接口&#xff0c;可以實時獲取到電商平臺上的各種數據&#xff0c;這些數據可以幫助企業或開發者做出及時的決策和分析。例如&…

vue動態修改audio地址

問題&#xff1a;點擊后替換url地址&#xff0c;實現了&#xff0c;但是播放器依舊沒有反應。 解決&#xff1a;vue中動態替換只是替換了地址&#xff0c;并沒有告訴audio標簽是否要執行&#xff0c;執行什么操作。要load后才能讓它知道&#xff0c;是在喊他&#xff0c;他需求…

秒懂算法 | 漢諾塔問題與木棒三角形

在數學與計算機科學中&#xff0c;遞歸(recursion)是指一個過程或函數在其定義或說明中又直接或間接調用自身的一種方法。它通常把一個大型復雜的問題層層轉化為一個與原問題相似的規模較小的問題來求解。遞歸策略只需少量的程序就可描述出解題過程所需要的多次重復計算&#x…

Android性能優化——線程優化

一、線程調度原理 在任意時刻&#xff0c;CPU只能執行一條指令&#xff0c;每個線程獲取到CPU的使用權之后才可以執行指令也就是說在任意時刻&#xff0c;只有一個線程占用CPU 處于運行狀態 多線程并發&#xff0c;實際上是指多個線程輪流獲取CPU 的使用權然后分別執行各自的任…

系統安全測試要怎么做?

進行系統安全測試時&#xff0c;可以按照以下詳細的步驟進行&#xff1a; 1、信息收集和分析&#xff1a; 收集系統的相關信息&#xff0c;包括架構、部署環境、使用的框架和技術等。 分析系統的安全需求、威脅模型和安全策略等文檔。 2、威脅建模和風險評估&#xff1a; 使…

調用被fishhook的原函數

OC類如果通過runtime被hook了&#xff0c;可以通過逆序遍歷方法列表的方式調用原方法。 那系統庫的C函數被fish hook了該怎么辦呢&#xff1f; 原理和OC類異曲同工&#xff0c;即通過系統函數dlopen()獲取動態庫&#xff0c;以動態庫為參數通過系統函數dlsym()即可獲取目標系統…

leetcode292. Nim 游戲(博弈論 - java)

Nim 游戲 Nim 游戲題目描述博弈論 上期經典算法 Nim 游戲 難度 - 簡單 原題鏈接 - Nim游戲 題目描述 你和你的朋友&#xff0c;兩個人一起玩 Nim 游戲&#xff1a; 桌子上有一堆石頭。 你們輪流進行自己的回合&#xff0c; 你作為先手 。 每一回合&#xff0c;輪到的人拿掉 1 -…

494. 目標和

494. 目標和 原題鏈接&#xff1a;完成情況&#xff1a;解題思路&#xff1a;數組回溯法動態規劃 參考代碼&#xff1a;數組回溯法__494目標和__動態規劃 經驗吸取 原題鏈接&#xff1a; 494. 目標和 https://leetcode.cn/problems/target-sum/description/ 完成情況&#…

Android進階之多級列表

遇到一個需求需要顯示多級列表&#xff0c;因為界面是在平板上的&#xff0c;所以層級是從左向右往下排的&#xff0c;類似于 我當時的寫法是在xml布局里一個個RecyclerView往下排的 當然前提是已經規定好最大的層級我才敢如此去寫界面&#xff0c;如果已經明確規定只有兩級或…

69 # 強制緩存的配置

強制緩存 強制緩存&#xff1a;以后的請求都不需要訪問服務器&#xff0c;狀態碼為 200協商緩存&#xff1a;每次都判斷一下&#xff0c;告訴是否需要找緩存&#xff0c;狀態碼為 304 默認強制緩存&#xff0c;不緩存首頁&#xff08;如果已經斷網&#xff0c;那這個頁面應該…