React16 diff全面讲解

本文详细探讨了React16中ChildReconciler、reconcileChildFibers、reconcileSingleElement和reconcileChildrenArray等方法在diff算法中的作用,包括节点的插入、更新和删除策略,以及key和type在决定节点复用中的关键角色。重点解析了顺序优化技术如何减少DOM操作,提高性能。
摘要由CSDN通过智能技术生成

本文较长,请耐心读完,相信我定有收货,如果有错误欢迎指正。

reconcileChildren 这个方法做的事情是对于刚创建的组件,会创建新的子 Fiber 节点,update 组件,将当前组件与该组件在上次更新时对应的 Fiber 节点比较(也就是俗称的 Diff 算法),将比较的结果生成新 Fiber 节点。

function reconcileChildren(current, workInProgress, nextChildren, renderExpirationTime) {
   
  // 首次渲染时只有root节点存在current,所以只有root会进入reconcile产生effectTag
  // 其他节点会appendAllChildren形成DOM树
  if (current === null) {
   
    workInProgress.child = mountChildFibers(
        workInProgress, null, nextChildren, renderExpirationTime
    );
  } else {
   
    workInProgress.child = reconcileChildFibers(
        workInProgress, current.child, nextChildren, renderExpirationTime
    );
  }
}

通过调试,current 首次渲染只有 root 上有值,其他节点为 null,等状态更新时候所有的 current 都会存在了,可以看到传入的参数还有一个 workInProgress,这个就是 react 中用到的双缓冲技术。

current 代表当前展示视图对应的 fiber 树,workInProgress 代表正在构建中的树,通过 alternate 连接。

workInProgress 构建完成后根节点又通过改变 current 指向 workInProgress,所以 wip 又变回了 current 树,其中在构建 wip 树的时候会选择性的复用 current 树节点。

另外通过初始渲染和更新渲染后都返回了 workInProgress.child 作为下个时间分片任务单元。

一、ChildReconciler总览

最上面的代码中有两个分支,初始加载和更新时,调用不同的方法,但是最终都是执行,通过参数区分:

var reconcileChildFibers = ChildReconciler(true);
var mountChildFibers = ChildReconciler(false);

但是这个方法 中做了很多的事情,大致看下结构:

function ChildReconciler(shouldTrackSideEffects) {
   
    function deleteChild(returnFiber, childToDelete) {
   }
    function deleteRemainingChildren(returnFiber, currentFirstChild) {
   }
    function mapRemainingChildren(...) {
   }
    function useFiber(...) {
   }
    function placeChild(...) {
   }
    function placeSingleChild(...) {
   }
    function updateTextNode(...) {
   }
    function updateElement(...) {
   }
    function updatePortal(...) {
   }
    function updateFragment(...) {
   }
    function createChild(...) {
   }
    function updateSlot(...) {
   }
    function updateFromMap(...) {
   }
    function warnOnInvalidKey(...) {
   }
    function reconcileChildrenArray(...) {
   }
    function reconcileChildrenIterator(...) {
   }
    function reconcileSingleTextNode(...) {
   }
    function reconcileSingleElement(...) {
   }
    function reconcileSinglePortal(...) {
   }
    function reconcileChildFibers(...) {
   }
    return reconcileChildFibers;
}

乍一看这个方法无从下手,从命名来看有插入、更新、删除、调和等关键信息,最后暴露出的是 reconcileChildFibers 方法,所以先从这里入手,大致了解其中做的事情。

二、reconcileChildFibers

function reconcileChildFibers(...): Fiber | null {
   
  // fragments <>{[...]}</> and <>...</>. 所以经常使用的fragments优化的点体现在这里,直接拿子节点
  ...
  if (isUnkeyedTopLevelFragment) {
   
    newChild = newChild.props.children;
  }

  // Handle object types
  const isObject = typeof newChild === 'object' && newChild !== null;
  //对象的形式
  if (isObject) {
   
    switch (newChild.$$typeof) {
   
      case REACT_ELEMENT_TYPE:
        return placeSingleChild(
          reconcileSingleElement(...),
        );
      case REACT_PORTAL_TYPE:
        ...
    }
  }
  //return 1 单个
  if (typeof newChild === 'string' || typeof newChild === 'number') {
   
    return placeSingleChild(
      reconcileSingleTextNode(...),
    );
  }
  //return [1,2,3] 节点中有并级  现在的业务中这里是一般必然要走的
  if (isArray(newChild
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值