React是如何將數(shù)據(jù)變化渲染到頁(yè)面的
針對(duì)這個(gè)問(wèn)題,我們需要對(duì)React有一個(gè)非常簡(jiǎn)單的宏觀的認(rèn)識(shí)。
React其實(shí)就是一個(gè)輸入數(shù)據(jù),然后根據(jù)數(shù)據(jù)產(chǎn)出頁(yè)面的函數(shù)。
我們帶著這個(gè)宏觀的認(rèn)識(shí)開(kāi)始從一次點(diǎn)擊事件開(kāi)始觀察react整個(gè)渲染的流程。
我們先創(chuàng)建一個(gè)最簡(jiǎn)單的react應(yīng)用。

當(dāng)我們點(diǎn)擊一個(gè)dom節(jié)點(diǎn)時(shí),我們可以從event對(duì)象中獲取到當(dāng)前事件發(fā)生的dom節(jié)點(diǎn)。而React中,我們給組件綁定一個(gè)onClick事件,其實(shí)事件并沒(méi)有被真正的注冊(cè)到dom上。React將大多數(shù)事件在整個(gè)應(yīng)用初次掛載的時(shí)候都綁定到了根節(jié)點(diǎn)上,當(dāng)真正的點(diǎn)擊事件發(fā)生時(shí),會(huì)先從event中拿到當(dāng)前事件發(fā)生的dom,從dom中獲取fiber對(duì)象,然后再一直沿父節(jié)點(diǎn)收集所有fiber上的onClick屬性,收集完成后再遍歷去執(zhí)行。



?而從button中收集到的onClick就會(huì)被執(zhí)行,setData其實(shí)就是useState返回的dispatchSetState函數(shù),主要就是創(chuàng)建update,開(kāi)啟調(diào)度。

update中保存了優(yōu)先級(jí),payload/action,next等信息,最終會(huì)在beginWork中,調(diào)用函數(shù)組件獲取子節(jié)點(diǎn)時(shí),通過(guò)usState更新,這個(gè)時(shí)候useState返回的就是更新后的state。具體更新邏輯在updateReducer這個(gè)函數(shù)中。

開(kāi)啟調(diào)度是為了通過(guò)messageChannel異步發(fā)起react更新。簡(jiǎn)單來(lái)說(shuō),就是為了運(yùn)行


等同步代碼頭執(zhí)行完,通過(guò)postMessage進(jìn)入到宏任務(wù)的task(performConcurrentWorkOnRoot/performSyncWorkOnRoot)將開(kāi)始執(zhí)行,先執(zhí)行workLoop函數(shù)對(duì)整個(gè)fiber進(jìn)行深度優(yōu)先遍歷,再執(zhí)行commitRoot完成更新。
workLoop函數(shù)會(huì)循環(huán)調(diào)用performUnitOfWork函數(shù)。

先執(zhí)行beginWork,根據(jù)對(duì)比更新的結(jié)果,給子節(jié)點(diǎn)打上增刪移等標(biāo)記。
在子節(jié)點(diǎn)為null時(shí),再調(diào)用completeWork,completeWork將會(huì)判斷HostComponent類(lèi)型的組件,也就是實(shí)際的dom的節(jié)點(diǎn),是否需要更新。需要的話(huà),就打上更新標(biāo)記。
completeWork還會(huì)將這些打了標(biāo)記的fiber節(jié)點(diǎn),添加到父節(jié)點(diǎn)的副作用隊(duì)列中,這樣在commit階段,只需要從根節(jié)點(diǎn)就可以拿到全部需要處理的fiber節(jié)點(diǎn),不用在此對(duì)fiber樹(shù)進(jìn)行遍歷。



等整個(gè)fiber樹(shù)都遍歷完,就可以執(zhí)行commitRoot函數(shù),對(duì)打了標(biāo)記的節(jié)點(diǎn)進(jìn)行處理。commitRoot會(huì)在dom更改之前,之后調(diào)用不同的我們?cè)诮M建中提供的勾子函數(shù)或者Effect Hooks。
我們主要看一下HostComponent,也就是真實(shí)dom在這個(gè)時(shí)候是如何更改的。因?yàn)榍捌谝呀?jīng)對(duì)需要更改的節(jié)點(diǎn)都打上了update標(biāo)記,所以會(huì)執(zhí)行commitUpdate函數(shù)。


根據(jù)不同屬性做不同處理,children其實(shí)也是一種屬性。我們此處是h1的children更改了,所以會(huì)執(zhí)行setTextContent函數(shù)。

將新的value,更新到dom上。

這樣,在點(diǎn)擊完成后,react就將更改真正的同步到了頁(yè)面上。