react解析: render的中的update(四)

感謝 yck: 剖析 React 源碼解析,本篇文章是在讀完他的文章的基礎上,將他的文章進行拆解和加工,加入我本身的一下理解和例子,便於你們理解。以爲yck寫的真的很棒 。React 版本爲 16.8.6,關於源碼的閱讀,能夠移步到yck react源碼解析html

本文永久有效連接: react解析: render的中的update(四)

上一章節說到,不存在root數據節點,即經過createFiberRoot 函數建立FiberRootFiberRoot對象是整個React應用的起點,同時也記錄了整個React應用更新過程當中的各類信息。react

下面將要聊到的就是,當root唄建立後,還會發生什麼👇👇git

legacyRenderSubtreeIntoContainer 函數

下面銜接上一部份內容,不懂得能夠查看上一章節github

yck: ReactDOM 源碼 554行 legacyRenderSubtreeIntoContainerapi

function legacyRenderSubtreeIntoContainer(
  parentComponent: ?React$Component<any, any>,
  children: ReactNodeList,
  container: DOMContainer,
  forceHydrate: boolean,
  callback: ?Function,
) {
    // 初始化時,container 確定沒有 _reactRootContainer屬性
    let root: Root = (container._reactRootContainer: any);
    if (!root) {
        // 省略建立root部分
        
        unbatchedUpdates(() => {
            if (parentComponent != null) {
                root.legacy_renderSubtreeIntoContainer(
                    parentComponent,
                    children,
                    callback,
                );
            } else {
                root.render(children, callback);
            }
        });
    }
}複製代碼

在root剛剛被建立時,parentComponent通常都爲null;數組

unbatchedUpdates函數在這裏做用是:告知React內部不進行批量更新,即不用將多個setState合併爲一個;
setState在後面的章節咱們將會說到bash

那麼這裏實際調用的就是root.render函數,root是ReactRoot實例對象,即調用 root.render函數 == ReactRoot.prototype.render函數dom

ReactRoot.prototype.render 函數

yck: ReactRoot 源碼 377行 ReactRoot.prototype.renderide

ReactRoot.prototype.render = function(
  children: ReactNodeList,
  callback: ?() => mixed,
): Work {
  // 這裏指 FiberRoot
  const root = this._internalRoot;
  const work = new ReactWork();
  callback = callback === undefined ? null : callback;

  // 若是有 callback,就 push 進 work 中的數組
  if (callback !== null) {
    work.then(callback);
  }
  // work._onCommit 就是用於執行全部回調函數的
  updateContainer(children, root, null, work._onCommit);
  return work;
};複製代碼

函數中的參數children便是ReactElement節點對象,callback爲回調函數。ReactWork實例對象的主要做用就是維護一個回調數組,可查看yck: ReactWork 源碼 327行,若是傳入參數中存在callback,就將其掛載ReactWork實例對象中;函數

下面來看看updateContainer函數會作什麼。

updateContainer 函數

yck: ReactFiberReconciler 源碼 284行 updateContainer

export function updateContainer(
  element: ReactNodeList,
  container: OpaqueRoot,
  parentComponent: ?React$Component<any, any>,
  callback: ?Function,
): ExpirationTime {
  const current = container.current;
  // 計算時間
  const currentTime = requestCurrentTime();
  // expirationTime 表明優先級,數字越大優先級越高
  // sync 的數字是最大的,因此優先級也是最高的
  const expirationTime = computeExpirationForFiber(currentTime, current);
  return updateContainerAtExpirationTime(
    element,
    container,
    parentComponent,
    expirationTime,
    callback,
  );
}複製代碼

container.current便是從FiberRoot中取出RootFiber對象,currentTime就是當前距離React應用初始化的時間。 **expirationTime字面意思就是過時時間,後面我會專門花一章的時間來介紹這兩個時間,這兩個時間也是React應用任務調度的重點。

scheduleRootUpdate函數

updateContainerAtExpirationTime函數實際調用的就是scheduleRootUpdate函數,下面來講一下scheduleRootUpdate函數的做用。

yck: ReactFiberReconciler 源碼 114行 scheduleRootUpdate

function scheduleRootUpdate(
  current: Fiber,
  element: ReactNodeList,
  expirationTime: ExpirationTime,
  callback: ?Function,
) {
  // 建立一個 update,就是內部有幾個屬性的對象
  const update = createUpdate(expirationTime);
  update.payload = {element};

  // render中的回調函數 
  callback = callback === undefined ? null : callback;
  if (callback !== null) {
    update.callback = callback;
  }

  flushPassiveEffects();
  // 把 update 入隊,內部就是一些建立或者獲取 queue(鏈表結構),而後給鏈表添加一個節點的操做
  enqueueUpdate(current, update);
  scheduleWork(current, expirationTime);

  return expirationTime;
}複製代碼

下面就是update對象其中的屬性:

// update對象屬性
export type Update<State> = {
  // 更新的過時時間
  expirationTime: ExpirationTime,

  // export const UpdateState = 0;
  // export const ReplaceState = 1;
  // export const ForceUpdate = 2;
  // export const CaptureUpdate = 3;
  // 指定更新的類型,值爲以上幾種
  tag: 0 | 1 | 2 | 3,
  // 更新內容,好比`setState`接收的第一個參數
  payload: any,
  // 對應的回調,`setState`,`render`都有
  callback: (() => mixed) | null,

  // 指向下一個更新
  next: Update<State> | null,
  // 指向下一個`side effect`
  nextEffect: Update<State> | null,
};複製代碼

udate對象會被插入到React應用維護的任務隊列中,無論你是setState仍是ReactDOM.render形成的 React應用 更新都是如此。這個函數核心做用就是建立或者獲取一個隊列,而後把 update 對象插入隊列進行更新。scheduleWork函數就是任務調度的東西了。

更多內容:

react解析: React.createElement(一)

react解析: React.Children(二)

react解析: render的FiberRoot(三)

參考:

yck: 剖剖析 React 源碼

Jokcy 的 《React 源碼解析》: react.jokcy.me/

ps: 順便推一下本身的我的公衆號:Yopai,有興趣的能夠關注,每週不按期更新,分享能夠增長世界的快樂

相關文章
相關標籤/搜索