最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

React Fiber構(gòu)建beginWork源碼解析

 更新時間:2023年02月06日 10:05:34   作者:GW_劉振  
這篇文章主要為大家介紹了React Fiber構(gòu)建beginWork源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

引言

前文我們介紹了fiber的基本概念,以及fiber在初始化階段生成了fiberRoot和rootFiber 2個對象。

但,整個fiber樹還沒有構(gòu)建,未進入reconciler階段。

本篇,我們將介紹,fiber鏈表的構(gòu)建之-beginWork階段

一. scheduleUpdateOnFiber

function scheduleUpdateOnFiber(fiber, lane, eventTime) {
  // ...
  if (root === workInProgressRoot) {
      {
        workInProgressRootUpdatedLanes = mergeLanes(workInProgressRootUpdatedLanes, lane);
      }
    }
  // ...
  if (lane === SyncLane) {
      if ( // Check if we're inside unbatchedUpdates
      (executionContext & LegacyUnbatchedContext) !== NoContext && // Check if we're not already rendering
      (executionContext & (RenderContext | CommitContext)) === NoContext) {
        // ...
        performSyncWorkOnRoot(root)
      }else {
        // ...
        ensureRootIsScheduled(root, eventTime);
      }
  }else {
    // ...
     ensureRootIsScheduled(root, eventTime);
     schedulePendingInteractions(root, lane);
  }
}

fiber在內(nèi)存中,會有兩份數(shù)據(jù),一個是當前的,一個是在內(nèi)存中正在構(gòu)建的。

這里 根據(jù)不同的啟動模式,進行下面的協(xié)調(diào)階段。在17版本中,一般使用sync模式。18版本默認開啟并發(fā)模式。

二. performSyncWorkOnRoot

同步模式下的流程,如果是并發(fā)模式,會進入schedule異步調(diào)度,最終還會執(zhí)行performSyncWorkOnRoot。

function performSyncWorkOnRoot(root) {
    flushPassiveEffects();
    var lanes;
    var exitStatus;
    if (root === workInProgressRoot && includesSomeLane(root.expiredLanes, workInProgressRootRenderLanes)) {
      lanes = workInProgressRootRenderLanes;
      exitStatus = renderRootSync(root, lanes);
      if (includesSomeLane(workInProgressRootIncludedLanes, workInProgressRootUpdatedLanes)) {
        lanes = getNextLanes(root, lanes);
        exitStatus = renderRootSync(root, lanes);
      }
    } else {
      lanes = getNextLanes(root, NoLanes);
      exitStatus = renderRootSync(root, lanes);
    }
    // ...
    var finishedWork = root.current.alternate;
    root.finishedWork = finishedWork;
    root.finishedLanes = lanes;
    commitRoot(root); 
    ensureRootIsScheduled(root, now());
    return null;
}

performSyncWorkOnRoot是reconciler階段所有的執(zhí)行入口,首次渲染將進入renderRootSync。

問題來了,為什么要先執(zhí)行flushPassiveEffects?這里留個懸念,在后續(xù)的更新流程中我們再提及。

關(guān)于nextLanes,這里我先拋開,先理解為render優(yōu)先級,lane模型會在后續(xù)章節(jié)系統(tǒng)性的講解。

renderRootSync

function renderRootSync(root, lanes) {
  if (workInProgressRoot !== root || workInProgressRootRenderLanes !== lanes) {
      prepareFreshStack(root, lanes); 
      startWorkOnPendingInteractions(root, lanes);
    }
   // ...
    do {
      try {
        workLoopSync();
        break;
      } catch (thrownValue) {
        handleError(root, thrownValue);
      }
    } while (true);
    // ...
}

prepare階段,可以構(gòu)建雙緩存fiber,即workInProgressRoot,內(nèi)存中的fiber通過之前的createFiber方法調(diào)用,當前fiber和內(nèi)存中fiber通過alternate相互引用。

workLoopSync即react兩大工作循環(huán)中的第一層循環(huán),從這里開始構(gòu)建fiber鏈表。

workLoopSync

function workLoopSync() {
    while (workInProgress !== null) {
      performUnitOfWork(workInProgress);
    }
  }

這里是同步構(gòu)建的情況,值得對比的是另外一個方法:

function workLoopConcurrent() {
    while (workInProgress !== null && !shouldYield()) {
      performUnitOfWork(workInProgress);
    }
  }

此方法是并發(fā)模式下的工作模式,兩者區(qū)別在于shouldYield。shouldYield由schedule調(diào)度器控制,react自己實現(xiàn)了一套瀏覽器空閑時的任務(wù)調(diào)度。 其實,瀏覽器本身有對應(yīng)的api:requestIdCallback。但不同瀏覽器執(zhí)行有時間差異,不能滿足react設(shè)計需要。

performUnitOfWork

function performUnitOfWork(unitOfWork) {
    var current = unitOfWork.alternate; 
    // ...
    var next;
    if ( (unitOfWork.mode & ProfileMode) !== NoMode) {
      startProfilerTimer(unitOfWork);
      next = beginWork$1(current, unitOfWork, subtreeRenderLanes);
      stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, true);
    } else {
      next = beginWork$1(current, unitOfWork, subtreeRenderLanes);
    }
    resetCurrentFiber();
    unitOfWork.memoizedProps = unitOfWork.pendingProps;
    if (next === null) {
      completeUnitOfWork(unitOfWork);
    } else {
      workInProgress = next;
    }
    ReactCurrentOwner$2.current = null;
  }

profile是react內(nèi)部性能跟蹤調(diào)試器,在正常的開發(fā)生產(chǎn)環(huán)境不會主動開啟,將進入beginWork階段

三. beginWork

  function beginWork(current, workInProgress, renderLanes) {
      if (current !== null) {
      var oldProps = current.memoizedProps;
      var newProps = workInProgress.pendingProps;
      if (oldProps !== newProps || hasContextChanged() || ( // Force a re-render if the implementation changed due to hot reload:
       workInProgress.type !== current.type )) {
        didReceiveUpdate = true;
      } else if (!includesSomeLane(renderLanes, updateLanes)) {
        didReceiveUpdate = false; 
        switch (workInProgress.tag) {
          // ...
        }
      } else {
        if ((current.flags & ForceUpdateForLegacySuspense) !== NoFlags) {
          didReceiveUpdate = true;
        } else {
          didReceiveUpdate = false;
        }
      }
    } else {
      didReceiveUpdate = false;
    } 
    workInProgress.lanes = NoLanes;
    switch (workInProgress.tag) {
      case IndeterminateComponent:
        {
          return mountIndeterminateComponent(current, workInProgress, workInProgress.type, renderLanes);
        }
      case LazyComponent:
        {
          var elementType = workInProgress.elementType;
          return mountLazyComponent(current, workInProgress, elementType, updateLanes, renderLanes);
        }
      case FunctionComponent:
        {
          var _Component = workInProgress.type;
          var unresolvedProps = workInProgress.pendingProps;
          var resolvedProps = workInProgress.elementType === _Component ? unresolvedProps : resolveDefaultProps(_Component, unresolvedProps);
          return updateFunctionComponent(current, workInProgress, _Component, resolvedProps, renderLanes);
        }
      case ClassComponent:
        {
          var _Component2 = workInProgress.type;
          var _unresolvedProps = workInProgress.pendingProps;
          var _resolvedProps = workInProgress.elementType === _Component2 ? _unresolvedProps : resolveDefaultProps(_Component2, _unresolvedProps);
          return updateClassComponent(current, workInProgress, _Component2, _resolvedProps, renderLanes);
        }
      case HostRoot:
        return updateHostRoot(current, workInProgress, renderLanes);
      case HostComponent:
        return updateHostComponent(current, workInProgress, renderLanes);
      case HostText:
        return updateHostText(current, workInProgress);
      case SuspenseComponent:
        return updateSuspenseComponent(current, workInProgress, renderLanes);
      case HostPortal:
        return updatePortalComponent(current, workInProgress, renderLanes);
      case ForwardRef:
        {
          var type = workInProgress.type;
          var _unresolvedProps2 = workInProgress.pendingProps;
          var _resolvedProps2 = workInProgress.elementType === type ? _unresolvedProps2 : resolveDefaultProps(type, _unresolvedProps2);
          return updateForwardRef(current, workInProgress, type, _resolvedProps2, renderLanes);
        }
      case Fragment:
        return updateFragment(current, workInProgress, renderLanes);
      case Mode:
        return updateMode(current, workInProgress, renderLanes);
      case Profiler:
        return updateProfiler(current, workInProgress, renderLanes);
      case ContextProvider:
        return updateContextProvider(current, workInProgress, renderLanes);
      case ContextConsumer:
        return updateContextConsumer(current, workInProgress, renderLanes);
      case MemoComponent:
        {
          var _type2 = workInProgress.type;
          var _unresolvedProps3 = workInProgress.pendingProps; // Resolve outer props first, then resolve inner props.
          var _resolvedProps3 = resolveDefaultProps(_type2, _unresolvedProps3);
          {
            if (workInProgress.type !== workInProgress.elementType) {
              var outerPropTypes = _type2.propTypes;
              if (outerPropTypes) {
                checkPropTypes(outerPropTypes, _resolvedProps3, // Resolved for outer only
                'prop', getComponentName(_type2));
              }
            }
          }
          _resolvedProps3 = resolveDefaultProps(_type2.type, _resolvedProps3);
          return updateMemoComponent(current, workInProgress, _type2, _resolvedProps3, updateLanes, renderLanes);
        }
      case SimpleMemoComponent:
        {
          return updateSimpleMemoComponent(current, workInProgress, workInProgress.type, workInProgress.pendingProps, updateLanes, renderLanes);
        }
      case IncompleteClassComponent:
        {
          var _Component3 = workInProgress.type;
          var _unresolvedProps4 = workInProgress.pendingProps;
          var _resolvedProps4 = workInProgress.elementType === _Component3 ? _unresolvedProps4 : resolveDefaultProps(_Component3, _unresolvedProps4);
          return mountIncompleteClassComponent(current, workInProgress, _Component3, _resolvedProps4, renderLanes);
        }
      case SuspenseListComponent:
        {
          return updateSuspenseListComponent(current, workInProgress, renderLanes);
        }
      case FundamentalComponent:
        {
          break;
        }
      case ScopeComponent:
        {
          break;
        }
      case Block:
        {
          {
            var block = workInProgress.type;
            var props = workInProgress.pendingProps;
            return updateBlock(current, workInProgress, block, props, renderLanes);
          }
        }
      case OffscreenComponent:
        {
          return updateOffscreenComponent(current, workInProgress, renderLanes);
        }
      case LegacyHiddenComponent:
        {
          return updateLegacyHiddenComponent(current, workInProgress, renderLanes);
        }
    }
  }

其中 didReceiveUpdate會在更新ref時使用到,也是props是否有變化的標志,這里先不關(guān)注。

首次將進入rootFiber的case,即HostRoot

updateHostRoot

function updateHostRoot(current, workInProgress, renderLanes) {
  // ...
  // 服務(wù)器端渲染處理先省略...
  // ...
  reconcileChildren(current, workInProgress, nextChildren, renderLanes);
  return workInProgress.child;
}

reconcileChildren

function reconcileChildren(current, workInProgress, nextChildren, renderLanes) {
    if (current === null) {
      // If this is a fresh new component that hasn't been rendered yet, we
      // won't update its child set by applying minimal side-effects. Instead,
      // we will add them all to the child before it gets rendered. That means
      // we can optimize this reconciliation pass by not tracking side-effects.
      workInProgress.child = mountChildFibers(workInProgress, null, nextChildren, renderLanes);
    } else {
      // If the current child is the same as the work in progress, it means that
      // we haven't yet started any work on these children. Therefore, we use
      // the clone algorithm to create a copy of all the current children.
      // If we had any progressed work already, that is invalid at this point so
      // let's throw it out.
      workInProgress.child = reconcileChildFibers(workInProgress, current.child, nextChildren, renderLanes);
    }
  }

對于首次渲染,current為Null,進入reconcileChildFibers

reconcileChildFibers

function reconcileChildFibers(returnFiber, currentFirstChild, newChild, lanes) {
  var isObject = typeof newChild === 'object' && newChild !== null;
      if (isObject) {
        switch (newChild.$$typeof) {
          case REACT_ELEMENT_TYPE:
            return placeSingleChild(reconcileSingleElement(returnFiber, currentFirstChild, newChild, lanes));
          case REACT_PORTAL_TYPE:
            return placeSingleChild(reconcileSinglePortal(returnFiber, currentFirstChild, newChild, lanes));
          case REACT_LAZY_TYPE:
            {
              var payload = newChild._payload;
              var init = newChild._init; // TODO: This function is supposed to be non-recursive.
              return reconcileChildFibers(returnFiber, currentFirstChild, init(payload), lanes);
            }
        }
      }
}

這里newChild是element對象,即render初始化階段所生成的react element。

這里,我們可以看到typeof了,除了是個symbol,防止偽造攻擊外,對于不同的類型,會有不同的fiber構(gòu)建流程。普通的typeof了,除了是個symbol,防止偽造攻擊外,對于不同的類型,會有不同的fiber構(gòu)建流程。普通的typeof了,除了是個symbol,防止偽造攻擊外,對于不同的類型,會有不同的fiber構(gòu)建流程。普通的typeof是element type。

reconcileSingleElement

function reconcileSingleElement(returnFiber, currentFirstChild, element, lanes) {
      var key = element.key;
      var child = currentFirstChild;
      // ... 如果存在child,遞歸刪除
      // ...
      if (element.type === REACT_FRAGMENT_TYPE) {
        var created = createFiberFromFragment(element.props.children, returnFiber.mode, lanes, element.key);
        created.return = returnFiber;
        return created;
      } else {
        var _created4 = createFiberFromElement(element, returnFiber.mode, lanes);
        _created4.ref = coerceRef(returnFiber, currentFirstChild, element);
        _created4.return = returnFiber;
        return _created4;
      }
}

createFiberFromElement

function createFiberFromElement(element, mode, lanes) {
    var owner = null;
    {
      owner = element._owner;
    }
    var type = element.type;
    var key = element.key;
    var pendingProps = element.props;
    var fiber = createFiberFromTypeAndProps(type, key, pendingProps, owner, mode, lanes);
    {
      fiber._debugSource = element._source;
      fiber._debugOwner = element._owner;
    }
    return fiber;
  }

根據(jù)element對象創(chuàng)建子節(jié)點fiber樹,并設(shè)置構(gòu)建的子fiber.return為父fiber。遍歷的方式使用的是深度優(yōu)先遍歷算法,一邊對子節(jié)點做fiber實例化,一邊對節(jié)點的上下關(guān)系做綁定

mountIndeterminateComponent

function mountIndeterminateComponent(_current, workInProgress, Component, renderLanes) {
  // ...
  prepareToReadContext(workInProgress, renderLanes);
  // ...
  setIsRendering(true);
  ReactCurrentOwner$1.current = workInProgress;
  value = renderWithHooks(null, workInProgress, Component, props, context, renderLanes);
  setIsRendering(false);
  // ...
  reconcileChildren(null, workInProgress, value, renderLanes);
  // ...
}

自定義組件,將先設(shè)置rendering狀態(tài)以及全局的render fiber進行時對象,自定義組件內(nèi)可能有副作用,比如useEffect,會影響flags。

renderWithHooks

function renderWithHooks(current, workInProgress, Component, props, secondArg, nextRenderLanes) {
  // ...
  {
      if (current !== null && current.memoizedState !== null) {
        ReactCurrentDispatcher$1.current = HooksDispatcherOnUpdateInDEV;
      } else if (hookTypesDev !== null) {
        ReactCurrentDispatcher$1.current = HooksDispatcherOnMountWithHookTypesInDEV;
      } else {
        ReactCurrentDispatcher$1.current = HooksDispatcherOnMountInDEV;
      }
    }
    var children = Component(props, secondArg);
    ReactCurrentDispatcher$1.current = ContextOnlyDispatcher;
}

ReactCurrentDispatcher對象很重要,這是effect處理重要的全局對象,他將改變flags值,并影響后續(xù)的effect鏈表構(gòu)建。

Component即函數(shù)組件對象,執(zhí)行的結(jié)果即element對象。此element對象將再次調(diào)用reconcileChildren,進入?yún)f(xié)調(diào)child階段,最終返回child的Fiber。

問題來了:

  • fiber是一邊生成,一邊關(guān)聯(lián)關(guān)系的,那么每層的fiber是如何找到下層element的?
  • 不同的fiber對象,updateQueue都一樣嗎?
  • 不同的fiber對象,memoizedState都一樣嗎?

對于rootFiber而言,updateQueue掛載的element對象,經(jīng)過process update,清空updateQueue.shared,進而將element對象掛載至memoizedState上,當執(zhí)行reconcileChildren時,nextChild從memoizedState獲取。

對于nextChild為function組件時,包括頂層函數(shù)組件,將執(zhí)行renderWithHooks,返回全量的element對象,當然renderWithHooks功能不僅僅于此,還涉及重要的flags計算。當執(zhí)行reconcileChildren時,會將element掛載至下層fiber的pendingProps上。

對于nextChild為普通節(jié)點時,會根據(jù)層層根據(jù)pendingProps獲取下一層節(jié)點的信息,從而繼續(xù)構(gòu)建fiber樹。

值得注意的是,函數(shù)組件節(jié)點的updateQueue指的是lastEffect鏈表,他其實是一個環(huán)狀鏈表結(jié)構(gòu)。

每個節(jié)點的構(gòu)建,都會設(shè)置memoizedProps = pendingProps

至此,beginWork的遞歸構(gòu)建已完成,下面將進入completeWork,更多關(guān)于React Fiber構(gòu)建beginWork的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • react數(shù)據(jù)管理中的setState與Props詳解

    react數(shù)據(jù)管理中的setState與Props詳解

    setState?是?React?中用于更新組件狀態(tài)(state)的方法,本文給大家介紹react數(shù)據(jù)管理中的setState與Props知識,感興趣的朋友跟隨小編一起看看吧
    2023-10-10
  • React導入less及其注意事項說明

    React導入less及其注意事項說明

    在Vite構(gòu)建的React項目中,直接安裝和導入Less即可使用,但需注意的是,Less的樣式作用域不局限于模塊內(nèi)部,可能造成樣式污染,建議通過修改文件名和導入方式來避免此問題
    2024-11-11
  • React創(chuàng)建組件的三種方式及其區(qū)別是什么

    React創(chuàng)建組件的三種方式及其區(qū)別是什么

    在React中,創(chuàng)建組件的三種主要方式是函數(shù)式組件、類組件和使用React Hooks的函數(shù)式組件,本文就詳細的介紹一下如何使用,感興趣的可以了解一下
    2023-08-08
  • react實現(xiàn)動態(tài)選擇框

    react實現(xiàn)動態(tài)選擇框

    這篇文章主要為大家詳細介紹了react實現(xiàn)動態(tài)選擇框,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-08-08
  • Javascript之提高React性能的技巧

    Javascript之提高React性能的技巧

    一些剛開始學習 React,或者從其他框架轉(zhuǎn)入 React 的開發(fā)者,一開始可能不會太關(guān)注性能。因為需要一些時間來發(fā)現(xiàn)新學習的框架的性能缺點。這篇文章主要介紹提高React性能的技巧,感興趣的同學可以參考閱讀
    2023-04-04
  • React受控組件與非受控組件詳細介紹

    React受控組件與非受控組件詳細介紹

    具體來說這是一種react非受控組件,其狀態(tài)是在input的react內(nèi)部控制,不受調(diào)用者控制。可以使用受控組件來實現(xiàn)。下面就說說這個React中的受控組件與非受控組件的相關(guān)知識,感興趣的朋友一起看看吧
    2022-09-09
  • React傳遞參數(shù)的幾種方式

    React傳遞參數(shù)的幾種方式

    本文詳細的介紹了React傳遞參數(shù)的幾種方式,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-06-06
  • 關(guān)于?React?中?useEffect?使用問題淺談

    關(guān)于?React?中?useEffect?使用問題淺談

    本文主要介紹了關(guān)于React中useEffect使用問題淺談,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-06-06
  • 使用React?MUI庫實現(xiàn)用戶列表分頁功能

    使用React?MUI庫實現(xiàn)用戶列表分頁功能

    MUI是一款基于React的UI組件庫,可以方便地構(gòu)建美觀的用戶界面,使用MUI的DataTable組件和分頁器組件可以輕松實現(xiàn)用戶列表分頁功能,這篇文章使用MUI庫實現(xiàn)了用戶列表分頁功能,感興趣的同學可以參考下文
    2023-05-05
  • 再次談?wù)揜eact.js實現(xiàn)原生js拖拽效果引起的一系列問題

    再次談?wù)揜eact.js實現(xiàn)原生js拖拽效果引起的一系列問題

    React 起源于 Facebook 的內(nèi)部項目,因為該公司對市場上所有 JavaScript MVC 框架,都不滿意,就決定自己寫一套,用來架設(shè) Instagram 的網(wǎng)站.本文給大家介紹React.js實現(xiàn)原生js拖拽效果,需要的朋友一起學習吧
    2016-04-04

最新評論

建水县| 蒙阴县| 连南| 蓬溪县| 准格尔旗| 伽师县| 汉沽区| 泰宁县| 唐河县| 常熟市| 徐水县| 灵石县| 墨玉县| 迭部县| 罗甸县| 武夷山市| 湖口县| 广饶县| 政和县| 海盐县| 化隆| 金川县| 唐河县| 三都| 拉孜县| 巴东县| 新竹市| 自贡市| 佳木斯市| 宁河县| 武隆县| 江阴市| 大荔县| 芜湖县| 澄城县| 德州市| 开江县| 延吉市| 广水市| 威宁| 将乐县|