這篇主要就是介紹render的一個流程,只到調度爲止,並無深刻到每一個點,涉及到的數據結構我會在下一篇專門列出來,這裏只要知道建立了什麼數據結構就能夠了,我主要是按16.12.0這個版本講的,今天發現已經更新到16.13.0了不過具體改了什麼還沒看react
export function render(element, container, callback) { // validate container return legacyRenderSubtreeIntoContainer( null, element, container, false, callback ); }
function legacyRenderSubtreeIntoContainer( parentComponent, children, container, forceHydrate, callback ) { let root = container._reactRootContainer; let fiberRoot; if (!root) { // ReactDOMBlockingRoot實例,屬性_internalRoot上掛載着fiberRootNode root = container._reactRootContainer = legacyCreateRootFromDOMContainer( container, forceHydrate ); fiberRoot = root._internalRoot; unbatchedUpdates(() => { updateContainer(children, fiberRoot, parentComponent, callback); }); } }
到這裏是一個極簡化的render,沒有進入任何分支,下面咱們看下ReactDOMBlockingRoot實例的建立,以及掛載在該實例下的FiberRoot數據結構
function legacyCreateRootFromDOMContainer(container, forceHydrate) { // 通常Hydrate的狀況是在服務端渲染和預渲染(prerender-spa-plugin) const shouldHydrate = forceHydrate || shouldHydrateDueToLegacyHeuristic(container); if (!shouldHydrate) { let rootSibling; while ((rootSibling = container.lastChild)) { container.removeChild(rootSibling); } } return createLegacyRoot( container, shouldHydrate ? { hydrate: true } : undefined ); }
export function createLegacyRoot(container, options = {}) { return new ReactDOMBlockingRoot(container, LegacyRoot, options); }
class ReactDOMBlockingRoot { // container:domElement, tag:rootType, options: {hydrate:boolean} constructor(container, tag, options) { this._internalRoot = createRootImpl(container, tag, options); } }
function createRootImpl(container, tag, options) { const hydrate = options !== null && options.hydrate === true; const hydrationCallbacks = (options != null && options.hydrationOptions) || null; // 拿到fiberRootNode const root = createContainer(container, tag, hydrate, hydrationCallbacks); // 講fiberNode 掛載到container對象上 markContainerAsRoot(root.current, container); return root; }
export function createContainer(container, tag, hydrate, hydrationCallbacks) { return createFiberRoot(container, tag, hydrate, hydrationCallbacks); }
export function createFiberRoot(container, tag, hydrate, hydrationCallbacks) { // 建立fiber樹root節點 const root = new FiberRootNode(container, tag, hydrate); const uninitializedFiber = createHostRootFiber(tag); root.current = uninitializedFiber; uninitializedFiber.stateNode = root; initializeUpdateQueue(uninitializedFiber); return root; }
接下來是render的建立完fiberRoot後的另一個分支unbatchedUpdatesdom
const NoContext = /* */ 0b000000; const BatchedContext = /* */ 0b000001; const EventContext = /* */ 0b000010; const DiscreteEventContext = /* */ 0b000100; const LegacyUnbatchedContext = /* */ 0b001000; const RenderContext = /* */ 0b010000; const CommitContext = /* */ 0b100000; let executionContext = NoContext; export function unbatchedUpdates(fn, a) { const prevExecutionContext = executionContext; // 去除executionContext上的BatchedContext executionContext &= ~BatchedContext; // 往executionContext上添加LegacyUnbatchedContext executionContext |= LegacyUnbatchedContext; // 進行回調 try { return fn(a); } finally { executionContext = prevExecutionContext; if (executionContext === NoContext) { // 刷新同步任務隊列 flushSyncCallbackQueue(); } } }
/** * * @param {*} element render的第一個參數 * @param {*} fiberRoot fiberRoot * @param {*} parentComponent 第一次渲染爲null * @param {*} callback render的第三個參數,一個回調 */ export function updateContainer(element, fiberRoot, parentComponent, callback) { const current = fiberRoot.current; // 這裏獲得的是到目前爲止 react還能處理多少單位時間(1單位時間是10ms) const currentTime = requestCurrentTimeForUpdate(); const suspenseConfig = requestCurrentSuspenseConfig(); // 計算過時時間,主要用在concurrent模式時使用 const expirationTime = computeExpirationForFiber( currentTime, current, suspenseConfig ); // 建立一個更新鏈表 const update = createUpdate(expirationTime, suspenseConfig); update.payload = { element }; // 處理回調函數 callback = callback === undefined ? null : callback; // 把建立的update添加到fiber的updateQueue上面 enqueueUpdate(current, update); // 進入調度 scheduleWork(current, expirationTime); return expirationTime; }
感受寫的很差,太難寫了,可是,看在我辛苦的份上動動小手點個贊哈哈,3q函數