最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • react fiber如何生成

    正文概述 掘金(若沉)   2020-12-24   501

    一、前言

      在之前的一篇文章中react fiber概念及原理,介绍了react v16中fiber扮演了什么样的一个角色,以及它的工作原理。概念和原理只能让你有一个初步的认识,想要深入的了解fiber,那么必须要从源码入手,看看fiber具体的实现是怎样的。接下来的内容将结合思维导图和代码描述react fiber在代码中如何生成。

    二、react三个阶段

      首先,react的设计理念是把整个应用看成是一个视图,当首屏渲染或者更新时,就会根据一系列过程生成新的视图,并渲染。这一系列过程伴随fiber的出现而发生了一些改变,react v16之前,react主要有两个阶段,分别是
      1.协调(Reconciler),根据状态的变化,找出变化的组件,并打上标记
      2.渲染(Renderder),根据被打上标记的组件,更新视图
      react v16及之后,react在原有两个阶段的基础上增加了一个调度过程(Scheduler),主要负责任务的调度(此文不涉及)
      而我们关心的fiber生成就是发生在在协调阶段(Reconciler)过程中,刚才我们说到,react在首屏渲染和更新时都会经历协调阶段,所以我们分首屏渲染和更新两种情况来看fiber生成过程。

    三、首屏渲染时的fiber

      根据react文档,reactDom创建应用有三种模式,分别是

      1. legacy -- ReactDOM.render(, rootNode)
      2. blocking -- ReactDOM.createBlockingRoot(rootNode).render()
      3. concurrent -- ReactDOM.createRoot(rootNode).render()

      此次我们讨论是的legacy模式,也是目前react默认的模式,我先根据react官方文档运行demo,看一下首屏渲染时的调用栈
    react fiber如何生成

    function legacyRenderSubtreeIntoContainer(parentComponent, children, container, forceHydrate, callback) {
      var root = container._reactRootContainer;
      var fiberRoot;
    
      if (!root) {
        // Initial mount
        root = container._reactRootContainer = legacyCreateRootFromDOMContainer(container, forceHydrate);
        fiberRoot = root._internalRoot;
        unbatchedUpdates(function () {
          updateContainer(children, fiberRoot, parentComponent, callback);
        });
      } else {
        //...do something
      }
    
      return getPublicRootInstance(fiberRoot);
    }
    

      在legacyRenderSubtreeIntoContainer中,因为是首次渲染,所以会创建rootFiberNode和rootFiber,然后将rootFiber作为此次渲染的workInProgress fiber,也就是一下renderRootSync函数中的第一个参数
      renderRootSync也就是开始创建fiber的入口函数

    function renderRootSync(root, lanes) {
      //...do something
      do {
        try {
          workLoopSync();
          break;
        } catch (thrownValue) {
          handleError(root, thrownValue);
        }
      } while (true);
      //...do something
      return workInProgressRootExitStatus;
    }
    
    function workLoopSync() {
      while (workInProgress !== null) {
        performUnitOfWork(workInProgress);
      }
    }
    
    function performUnitOfWork(unitOfWork) {
      var current = unitOfWork.alternate;
      setCurrentFiber(unitOfWork);
      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;
    }
    

      从代码上看react会执行一次循环,最终会运行performUnitOfWork这个函数,上面代码看着比较难懂,这里结合图来理解一下。我们知道fiber是类似于链表的数据结构,那么reactDom其实是通过递归的方式生成fiber,递阶段就是beginWork(最终调用createFiberFromElement返回一个fiber节点),归阶段就是completeWork(生成dom并挂载在父节点,更新处理props以及生成副作用链表),我们用图解的方式来表示一下整个递归的过程,假设我们的jsx是这样的结构

    <div>
        <header>
        	<span>test</span>
            这是一个头
        </header>
        <p>这也是一段话</p>
    </div>
    

    那么它对应的fiber数据就是
    react fiber如何生成
    所以整个过程就是:

    1. 递阶段(beginWork)依次生成div、header、span的fiber,span没有child,所以进行2流程
    2. 归阶段(completeWork)处理span、header,生成dom,赋值为stateNode属性,并挂载到父节点的dom上,header有一个sibling节点,所以进行3流程
    3. 递阶段(beginWork)生成p的fiber,p没有child,所以进行4流程
    4. 归阶段(completeWork)处理p、div,rootFiber生成dom,赋值为stateNode属性,并挂载到父节点的dom上

    如此可以得到最终的一个fiber数据结构,且应用的根节点其中rootFiber已经有了一个完整的dom树,然后进行渲染(Renderer)

    四、更新时的fiber

      上面说到react的设计理念是将整个应用看做是一个视图,所以reactDom在开始Reconciler时都是以rootFiber为起点。在更新时,当rooFiber的alternate不存在时,会克隆一个current fiber作为此次的workInProgress fiber,当rootFiber的alternate存在时,就将其作为此次更新的workInProgress。然后同样的进行上面的描述的流程。不同的是这次递归会在递阶段根据需要更新组件的jsx和workInProgress fiber进行对比生成新的fiber,也就是大名鼎鼎的diff算法。(alternate在此文中介绍react fiber概念及原理)


    起源地下载网 » react fiber如何生成

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元