欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

ReactDOM.render在react源碼中執(zhí)行原理

 更新時間:2022年12月19日 10:45:38   作者:flyzz177  
這篇文章主要為大家介紹了ReactDOM.render在react源碼中執(zhí)行原理解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

ReactDOM.render

通常是如下圖使用,在提供的 container 里渲染一個 React 元素,并返回對該組件的引用(或者針對無狀態(tài)組件返回 null)。

本文主要是將ReactDOM.render的執(zhí)行流程在后續(xù)文章中會對創(chuàng)建更新的細節(jié)進行分析,文中的源代碼部分為了方便閱讀將__DEV__部分的代碼移除掉了。

ReactDOM.render(
  <App />,
  document.getElementById('root')
);

render

位于:react-dom/src/client/ReactDOMLegacy.js

export function render(
  element: React$Element<any>,  container: Container,  callback: ?Function,
) {
  // 驗證container是否為有效的DOM節(jié)點
  invariant(
    isValidContainer(container),
    'Target container is not a DOM element.',
  );
  return legacyRenderSubtreeIntoContainer(
    null,
    element,
    container,
    false,
    callback,
  );
}

返回了一個legacyRenderSubtreeIntoContainer函數(shù),這里注意有5個參數(shù)

parentComponent: 父組件因為是初次創(chuàng)建所以為null。

children: 傳入的ReactElement

container: 渲染React的DOM容器

forceHydrate: 判斷是否需要協(xié)調,在服務端渲染的情況下已渲染的DOM結構是類似的因此可以在對比后進行復用。在服務端渲染的情況下使用ReactDOM.hydrate()與 render() 相同只是forceHydrate會標記為true。

callback: 渲染完成后的回調函數(shù)

legacyRenderSubtreeIntoContainer

位于:react-dom/src/client/ReactDOMLegacy.js作用:

  • 判斷是否為初次渲染,如果是就創(chuàng)建root并將root._internalRoot賦值給fiberRoot同時封裝callback回調,然后調用unbatchedUpdates立即更新子節(jié)點。
  • 如果不是第一次渲染則進入正常的updateContainer流程。
  • 最后getPublicRootInstance(fiberRoot)返回公開的 Root 實例對象。
function legacyRenderSubtreeIntoContainer(
  parentComponent: ?React$Component<any, any>,
  children: ReactNodeList,
  container: Container,
  forceHydrate: boolean,
  callback: ?Function,
) {
  // TODO: Without `any` type, Flow says "Property cannot be accessed on any
  // member of intersection type." Whyyyyyy.
  let root: RootType = (container._reactRootContainer: any);
  let fiberRoot;
  if (!root) {
    // Initial mount 初次渲染創(chuàng)建FiberRoot
    root = container._reactRootContainer = legacyCreateRootFromDOMContainer(
      container,
      forceHydrate,
    );
    fiberRoot = root._internalRoot;
    if (typeof callback === 'function') {
      const originalCallback = callback;
      callback = function() {
        const instance = getPublicRootInstance(fiberRoot);
        originalCallback.call(instance);
      };
    }
    // Initial mount should not be batched.
    unbatchedUpdates(() => {
      updateContainer(children, fiberRoot, parentComponent, callback);
    });
  } else {
    fiberRoot = root._internalRoot;
    if (typeof callback === 'function') {
      const originalCallback = callback;
      callback = function() {
        const instance = getPublicRootInstance(fiberRoot);
        originalCallback.call(instance);
      };
    }
    // Update
    updateContainer(children, fiberRoot, parentComponent, callback);
  }
  return getPublicRootInstance(fiberRoot);
}

legacyCreateRootFromDOMContainer

位于:react-dom/src/client/ReactDOMLegacy.js初次渲染進入創(chuàng)建root的環(huán)節(jié):root = container._reactRootContainer = legacyCreateRootFromDOMContainer(container, forceHydrate)作用:主要是判斷是否為服務端渲染,如果是的話就會復用存在的dom節(jié)點進行協(xié)調(reconciliation)提高性能,如果不是則會清空container中的子元素,最后傳入container和shouldHydrate返回createLegacyRoot函數(shù)。

function legacyCreateRootFromDOMContainer(
  container: Container,  forceHydrate: boolean,
): RootType {
  const shouldHydrate =
    forceHydrate || shouldHydrateDueToLegacyHeuristic(container); // 判斷是否是服務端渲染
  // First clear any existing content.
  if (!shouldHydrate) {
    let warned = false;
    let rootSibling;
    while ((rootSibling = container.lastChild)) {
      container.removeChild(rootSibling);
    }
  }
  return createLegacyRoot(
    container,
    shouldHydrate
      ? {
          hydrate: true,
        }
      : undefined,
  );
}

createLegacyRoot

位于:react-dom/src/client/ReactDOMRoot.js作用:返回了一個ReactDOMBlockingRoot實例,這里傳入了LegacyRoot是一個常量=0代表著現(xiàn)在使用的同步渲染模式,是為了后續(xù)的Concurrent可中斷渲染模式做準備。

export function createLegacyRoot(  container: Container,  options?: RootOptions, // hydrate
): RootType {
  return new ReactDOMBlockingRoot(container, LegacyRoot, options);
}

ReactDOMBlockingRoot

位于:react-dom/src/client/ReactDOMRoot.js作用:將createRootImpl函數(shù)的返回(FiberRoot)掛載到實例的_internalRoot上

function ReactDOMBlockingRoot(
  container: Container,  tag: RootTag,  options: void | RootOptions,
) {
  this._internalRoot = createRootImpl(container, tag, options);
}

createRootImpl

位于:react-dom/src/client/ReactDOMRoot.js作用:執(zhí)行createContainer拿到FiberRootNode并賦值給root,再通過markContainerAsRoot將RootFiber掛載到container上。

function createRootImpl(
  container: Container,
  tag: RootTag,
  options: void | RootOptions,
) {
  // Tag is either LegacyRoot or Concurrent Root
  const hydrate = options != null && options.hydrate === true;
  const hydrationCallbacks =
    (options != null && options.hydrationOptions) || null;
    // 拿到FiberRootNode
  const root = createContainer(container, tag, hydrate, hydrationCallbacks);
  // 將FiberRootNode掛載到container
  markContainerAsRoot(root.current, container);
  if (hydrate && tag !== LegacyRoot) {
    const doc =
      container.nodeType === DOCUMENT_NODE
        ? container
        : container.ownerDocument;
    eagerlyTrapReplayableEvents(container, doc);
  }
  return root;
}

createContainer

位于:react-reconciler/src/ReactFiberReconciler.old.js 作用:返回createFiberRoot

export function createContainer(  containerInfo: Container,  tag: RootTag,  hydrate: boolean,  hydrationCallbacks: null | SuspenseHydrationCallbacks,): OpaqueRoot {
  return createFiberRoot(containerInfo, tag, hydrate, hydrationCallbacks);
}

createFiberRoot

位于:react-reconciler/src/react-reconciler/src/ReactFiberReconciler.old.js 作用: 新建FiberRoot對象并賦值給root,初始化Fiber(通常叫做RootFiber)通過root.current = uninitializedFiber和uninitializedFiber.stateNode = root將兩者聯(lián)系起來。

執(zhí)行initializeUpdateQueue(uninitializedFiber)創(chuàng)建一個更新隊列,掛載fiber.updateQueue下面
最后將root返回

export function createFiberRoot(  containerInfo: any,  tag: RootTag,  hydrate: boolean,  hydrationCallbacks: null | SuspenseHydrationCallbacks,): FiberRoot {
  // 新建fiberRoot對象
  const root: FiberRoot = (new FiberRootNode(containerInfo, tag, hydrate): any);
  if (enableSuspenseCallback) {
    root.hydrationCallbacks = hydrationCallbacks;
  }
  // Cyclic construction. This cheats the type system right now because
  // stateNode is any.
  //初始化RootFiber
  const uninitializedFiber = createHostRootFiber(tag);
  root.current = uninitializedFiber;
  // RootFiber的stateNode指向FiberRoot
  uninitializedFiber.stateNode = root;
  initializeUpdateQueue(uninitializedFiber);
  return root;
}

FiberRoot RootFiber 和 updateQueue

ReactDOM.render主要創(chuàng)建了三個對象FiberRooat、RootFiber和Updatequeue下面我們這對這三個對象進行分析

FiberRoot

FiberRoot是FiberRootNode(containerInfo, tag, hydrate)的實例
位于:react-reconciler/src/ReactFiberRoot/FiberRootNode作用:

  • 整個應用的起點
  • 包含應用掛載的目標節(jié)點
  • 記錄整個應用更新過程的各種信息
function FiberRootNode(containerInfo, tag, hydrate) {
  // 標記不同的組件類型
  this.tag = tag;
  // 當前應用對應的Fiber對象,是Root Fiber
  // current:Fiber對象 對應的是 root 節(jié)點,即整個應用根對象
  this.current = null;
  // root節(jié)點,render方法接收的第二個參數(shù)
  this.containerInfo = containerInfo;
   // 只有在持久更新中會用到,也就是不支持增量更新的平臺,react-dom不會用到
  this.pendingChildren = null;
  this.pingCache = null;
  //任務有三種,優(yōu)先級有高低:
  //(1)沒有提交的任務
  //(2)沒有提交的被掛起的任務
  //(3)沒有提交的可能被掛起的任務
   //當前更新對應的過期時間
  this.finishedExpirationTime = NoWork;
  //已經(jīng)完成任務的FiberRoot對象,如果你只有一個Root,那么該對象就是這個Root對應的Fiber或null
  //在commit(提交)階段只會處理該值對應的任務
  this.finishedWork = null;
  // 在任務被掛起的時候通過setTimeout設置的返回內容,用來下一次如果有新的任務掛起時清理還沒觸發(fā)的timeout(例如suspense返回的promise)
  this.timeoutHandle = noTimeout;
  // 頂層context對象,只有主動調用renderSubTreeIntoContainer時才會被調用
  this.context = null;
  this.pendingContext = null;
  // 第一次渲染是否需要調和
  this.hydrate = hydrate;
  // Node returned by Scheduler.scheduleCallback
  this.callbackNode = null;
  this.callbackPriority = NoPriority;
  //存在root中,最舊的掛起時間
  //不確定是否掛起的狀態(tài)(所有任務一開始均是該狀態(tài))
  this.firstPendingTime = NoWork;
  this.firstSuspendedTime = NoWork;
  this.lastSuspendedTime = NoWork;
  this.nextKnownPendingLevel = NoWork;
  //存在root中,最新的掛起時間
  //不確定是否掛起的狀態(tài)(所有任務一開始均是該狀態(tài))
  this.lastPingedTime = NoWork;
  this.lastExpiredTime = NoWork;
  this.mutableSourcePendingUpdateTime = NoWork;
  if (enableSchedulerTracing) {
    this.interactionThreadID = unstable_getThreadID();
    this.memoizedInteractions = new Set();
    this.pendingInteractionMap = new Map();
  }
  if (enableSuspenseCallback) {
    this.hydrationCallbacks = null;
  }
}

RootFiber

RootFiber初始化于const uninitializedFiber = createHostRootFiber(tag) 通過 createFiber 返回 FiberNode的實例 作用:

  • 每個ReactElement對應一個Fiber對象
  • 記錄節(jié)點的各種狀態(tài)(方便了hooks,因為記錄state和props都是在Fiber只是完成后再掛載到this的例如:pendingProps pendingState memoizedProps memoizedState)
  • 串聯(lián)整個應用形成樹結構
// 位于 react-reconciler/src/ReactFiber.js
export function createHostRootFiber(tag: RootTag): Fiber {
  let mode;
  if (tag === ConcurrentRoot) {
    mode = ConcurrentMode | BlockingMode | StrictMode;
  } else if (tag === BlockingRoot) {
    mode = BlockingMode | StrictMode;
  } else {
    mode = NoMode;
  }
  return createFiber(HostRoot, null, null, mode);
}
const createFiber = function(
  tag: WorkTag,
  pendingProps: mixed,
  key: null | string,
  mode: TypeOfMode,
): Fiber {
  return new FiberNode(tag, pendingProps, key, mode);
};
// FiberNode結構
function FiberNode(
  tag: WorkTag,
  pendingProps: mixed,
  key: null | string,
  mode: TypeOfMode,
) {
  // Instance
  // 標記不同的組件類型
  this.tag = tag;
  // ReactElement里面的key
  this.key = key;
  // ReactElement.type,也就是我們調用`createElement`的第一個參數(shù)
  this.elementType = null;
  // 異步組件lazy component resolved之后返回的內容,一般是`function`或者`class`組件
  this.type = null;
  // 對應節(jié)點的實例,比如類組件就是class的實例,如果是dom組件就是dom實例,如果是function component就沒有實例這里為空
  this.stateNode = null;
  // Fiber Fiber是個鏈表通過child和Sibling連接,遍歷的時候先遍歷child如果沒有子元素了則訪問return回到上級查詢是否有sibling
  // 指向他在Fiber節(jié)點樹中的‘parent',用來在處理完這個節(jié)點之后向上返回
  this.return = null;
  // 指向第一個子節(jié)點
  this.child = null;
  // 指向自己的兄弟節(jié)點,兄弟節(jié)點的return指向同一個副節(jié)點
  this.sibling = null;
  this.index = 0;
  this.ref = null;
  // 新的變動帶來的新的props
  this.pendingProps = pendingProps;
  // 上次渲染完成后的props
  this.memoizedProps = null;
  // 該Fiber對應的組件產生的update會存放在這個隊列(比如setState和forceUpdate創(chuàng)建的更新)
  this.updateQueue = null;
  // 上一次的state
  this.memoizedState = null;
  this.dependencies = null;
  // 
  this.mode = mode;
  // Effects
  // 用來記錄副作用
  this.effectTag = NoEffect;
  // 單鏈表用來快速查找下一個side effect
  this.nextEffect = null;
  // 子樹中第一個side effect
  this.firstEffect = null;
  // 子樹中最后一個side effect
  this.lastEffect = null;
  // 代表任務在未來的哪個時候應該被完成 就是過期時間
  // 不包括他的子樹產生的任務
  this.expirationTime = NoWork;
  // 快速確定子樹中是否有不再等待的變化
  this.childExpirationTime = NoWork;
  // Fiber樹更新過程中,每個FIber都會有一個跟其對應的Fiber
  // 我們稱他為`current <==> workInProgress`
  // 渲染完成后他們會交換位置
  this.alternate = null;
  // 調試相關的去掉了
}

updateQueue

initializeUpdateQueue(uninitializedFiber);位于:react-reconciler/src/ReactUpdateQueue.js作用:單向鏈表,用來存放update,next來串聯(lián)update
關于Update和UpdateQueue涉及到的東西比較多打算單獨一章來講解

export function initializeUpdateQueue<State>(fiber: Fiber): void {
  const queue: UpdateQueue<State> = {
    // 每次操作完更新阿之后的state
    baseState: fiber.memoizedState,
    // 隊列中的第一個`Update`
    firstBaseUpdate: null,
    // 隊列中的最后一個`Update`
    lastBaseUpdate: null,
    shared: {
      pending: null,
    },
    effects: null,
  };
  fiber.updateQueue = queue;
}

流程圖

最后是畫的大致流程圖

以上就是ReactDOM.render在react源碼中執(zhí)行原理的詳細內容,更多關于react ReactDOM.render執(zhí)行原理的資料請關注腳本之家其它相關文章!

相關文章

  • 詳解使用React進行組件庫開發(fā)

    詳解使用React進行組件庫開發(fā)

    本篇文章主要介紹了詳解使用React進行組件庫開發(fā),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-02-02
  • Remix中mdx?table不支持表格解決

    Remix中mdx?table不支持表格解決

    這篇文章主要為大家介紹了Remix中mdx?table不支持表格問題解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-05-05
  • React?split實現(xiàn)分割字符串的使用示例

    React?split實現(xiàn)分割字符串的使用示例

    當我們需要將一個字符串按照指定的分隔符進行分割成數(shù)組時,我們可以在組件的生命周期方法中使用split方法來實現(xiàn)這個功能,本文就來介紹一下,感興趣的可以了解下
    2023-10-10
  • React?中的?setState?是同步還是異步

    React?中的?setState?是同步還是異步

    這篇文章主要介紹了React?中的?setState?是同步還是異步,文章圍繞主題展開詳細的內容介紹,具有一定的參考價值,需要的小伙伴可以參考一下
    2022-06-06
  • react項目中使用插件配置路由的方法

    react項目中使用插件配置路由的方法

    這篇文章主要介紹了react項目中使用插件配置路由的相關知識,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-03-03
  • React Native實現(xiàn)簡單的登錄功能(推薦)

    React Native實現(xiàn)簡單的登錄功能(推薦)

    這篇文章主要介紹了React Native實現(xiàn)登錄功能的相關資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2016-09-09
  • React18中的useDeferredValue示例詳解

    React18中的useDeferredValue示例詳解

    這篇文章主要介紹了React18中的useDeferredValue的相關知識,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-03-03
  • React 組件中實現(xiàn)事件代理

    React 組件中實現(xiàn)事件代理

    React的事件系統(tǒng)和瀏覽器事件系統(tǒng)相比,主要增加了兩個特性:事件代理、和事件自動綁定,本文主要介紹了React 組件中實現(xiàn)事件代理,具有一定的參考價值,感興趣的可以了解一下
    2024-01-01
  • 如何解決React官方腳手架不支持Less的問題(小結)

    如何解決React官方腳手架不支持Less的問題(小結)

    這篇文章主要介紹了如何解決React官方腳手架不支持Less的問題(小結),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-09-09
  • 基于PixiJS實現(xiàn)react圖標旋轉動效

    基于PixiJS實現(xiàn)react圖標旋轉動效

    PixiJS是一個開源的基于web的渲染系統(tǒng),為游戲、數(shù)據(jù)可視化和其他圖形密集型項目提供了極快的性能,這篇文章主要介紹了用PixiJS實現(xiàn)react圖標旋轉動效,需要的朋友可以參考下
    2022-05-05

最新評論