您好,登錄后才能下訂單哦!
這篇文章主要介紹了React怎么更新流程驅(qū)動(dòng)的相關(guān)知識(shí),內(nèi)容詳細(xì)易懂,操作簡(jiǎn)單快捷,具有一定借鑒價(jià)值,相信大家閱讀完這篇React怎么更新流程驅(qū)動(dòng)文章都會(huì)有所收獲,下面我們一起來(lái)看看吧。
首先我們書(shū)寫(xiě)的函數(shù)式組件、類(lèi)組件、jsx等代碼全部會(huì)被babel-react編譯成react.createElement()的調(diào)用或者jsx()調(diào)用(取決于react版本)。
舉個(gè)栗子:
<div> <ul> <li key='1'>1</li> <li key='2'>2</li> <li key='3'>3</li> </ul> </div>
轉(zhuǎn)換成
React.createElement( 'div', null, React.createElement( 'ul', null, React.createElement( 'li', { key: '1' }, '1' ), React.createElement( 'li', { key: '2' }, '2' ), React.createElement( 'li', { key: '3' }, '3' ) ) );
接下來(lái)我們需要知道React.createElement內(nèi)部到底做了什么?源碼位置
內(nèi)部的實(shí)現(xiàn)其實(shí)很簡(jiǎn)單,就是處理傳入的type/config/children等參數(shù),再返回一個(gè)新的對(duì)象。
從config中分離出特殊屬性 key 和 ref
將普通屬性以及children添加到props中
最后返回一個(gè)對(duì)象,這個(gè)對(duì)象我們稱之為ReactElement元素
ReactElement數(shù)據(jù)結(jié)構(gòu)如下:
const element = { $$typeof: REACT_ELEMENT_TYPE, type, key, ref, props, };
'$$typeof':ReactElement的標(biāo)識(shí)
'type':可能是'div' 'span'這樣的字符串標(biāo)簽,也可以是個(gè)函數(shù)(函數(shù)式組件)、類(lèi)(類(lèi)組件)
'key/ref/props': ReactElement的屬性
所以上述栗子的調(diào)用結(jié)果是下面的樹(shù)形結(jié)構(gòu):
{ type: 'div', key: null, ref: null, props: { children: { type: 'ul', key: null, ref: null, props: { children: [ { type: 'li', key: null, ref: null, props: { children: '1' } }, { type: 'li', key: null, ref: null, props: { children: '2' } }, { type: 'li', key: null, ref: null, props: { children: '3' } } ] } } } }
到這里就已經(jīng)完成第一個(gè)和第二個(gè)小目標(biāo)。
不過(guò)在這里要多提一下,上述的樹(shù)形結(jié)構(gòu),在react15版本及以前就可以直接拿來(lái)diff以及生成頁(yè)面,不過(guò)正如第一篇文章所說(shuō),這樣會(huì)遇到很大的問(wèn)題(任務(wù)過(guò)重js執(zhí)行時(shí)間久,影響渲染)。
所以16之后做的事情,就是依據(jù)上述的樹(shù)形結(jié)構(gòu)進(jìn)行重構(gòu),重構(gòu)出來(lái)的fiber數(shù)據(jù)結(jié)構(gòu)用于滿足異步渲染之需。
上篇文章中已經(jīng)介紹了fiber節(jié)點(diǎn)的數(shù)據(jù)結(jié)構(gòu),這里我們?cè)俳榻B下fiberRoot以及rootFiber。 fiberRoot源碼位置
FiberRoot數(shù)據(jù)結(jié)構(gòu):
class FiberRootNode { current: FiberNode; container: any | null; finishedWork: FiberNode | null; pendingLanes: Lanes; finishedLane: Lane; pendingPassiveEffects: PendingPassiveEffects; constructor(container: any | null, hostRootFiber: FiberNode) { this.current = hostRootFiber; this.container = container; hostRootFiber.stateNode = this; this.finishedWork = null; this.pendingLanes = NoLanes; this.finishedLane = NoLane; this.pendingPassiveEffects = { unmount: [], update: [] }; } }
其中很多屬性我們暫時(shí)無(wú)視,后續(xù)涉及到的時(shí)候會(huì)詳細(xì)講解,這里重點(diǎn)關(guān)注節(jié)點(diǎn)的關(guān)系。 rootFiber的數(shù)據(jù)結(jié)構(gòu)和普通的FiberNode節(jié)點(diǎn)區(qū)別不大,這里不再贅述~
整個(gè)React應(yīng)用有且只有一個(gè)fiberRoot
整個(gè)應(yīng)用中同時(shí)存在兩棵rootFiber樹(shù)
當(dāng)前頁(yè)面對(duì)應(yīng)的稱為currentFiber,另外一顆在內(nèi)存中構(gòu)建的稱為workInProgressFiber,它們通過(guò)alternate屬性連接。
fiberRoot中的current指針指向了currentFiber樹(shù)。
當(dāng)整個(gè)應(yīng)用更新完成,fiberRoot會(huì)修改current指針指向內(nèi)存中構(gòu)建好的workInProgressFiber。
圖形描述如下:
在mount階段的時(shí)候,應(yīng)用是需要一個(gè)執(zhí)行函數(shù)的,而這個(gè)函數(shù)就是(源碼位置)
react.createRoot(root).render(<App/>)
root
: 模版文件中的id為root的div
<App>
: 整個(gè)應(yīng)用的根組件
源碼簡(jiǎn)化后的代碼如下:
const createRoot = (container: Container) => { const root = createContainer(container); return { render(element: ReactElementType) { return updateContainer(element, root); } }; };
createRoot會(huì)返回一個(gè)對(duì)象,其中包含了render函數(shù),我們具體看看createContainer做了哪些事情。
const createContainer = (container: Container) => { // 創(chuàng)建rootFiber const hostRootFiber = new FiberNode(HostRoot, {}, null); // 創(chuàng)建fiberRoot const root = new FiberRootNode(container, hostRootFiber); hostRootFiber.updateQueue = createUpdateQueue(); return root; };
react.createRoot()在內(nèi)部會(huì)去創(chuàng)建整個(gè)應(yīng)用唯一的fiberRoot和rootFiber,并進(jìn)行關(guān)聯(lián)。(如上述圖形結(jié)構(gòu))
render內(nèi)部執(zhí)行的是updateContainer(),我們查看下內(nèi)部實(shí)現(xiàn):
const updateContainer = ( element: ReactElementType, root: FiberRootNode ) => { // mount時(shí) const hostRootFiber = root.current; // 添加update任務(wù) const lane = requestUpdateLane(); const update = createUpdate<ReactElementType | null>(element, lane); enqueueUpdate( hostRootFiber?.updateQueue as UpdateQueue<ReactElementType | null>, update ); scheduleUpdateOnFiber(hostRootFiber, lane); return element; };
其中有很多地方我們此時(shí)無(wú)須關(guān)心,但是我們看到內(nèi)部調(diào)用了scheduleUpdateOnFiber, 而這個(gè)就是更新流程(schedule(調(diào)度)->reconciler(協(xié)調(diào))->commit (渲染))的入口。
而這個(gè)入口不僅僅在初始化執(zhí)行函數(shù)中render調(diào)用會(huì)喚起,還有其他的方式:
類(lèi)組件中setState -> scheduleUpdateOnFiber()
函數(shù)組件useState -> scheduleUpdateOnFiber()
關(guān)于“React怎么更新流程驅(qū)動(dòng)”這篇文章的內(nèi)容就介紹到這里,感謝各位的閱讀!相信大家對(duì)“React怎么更新流程驅(qū)動(dòng)”知識(shí)都有一定的了解,大家如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。