资讯专栏INFORMATION COLUMN

React Fiber源码分析 第一篇

amc / 1147人阅读

摘要:系列文章源码分析第一篇源码分析第二篇同步模式源码分析第三篇异步状态源码分析第四篇归纳总结前言是在版本中的大更新,利用了闲余时间看了一些源码,做个小记录流程图源码分析先由编译,调用,入参为,打印出来可以看到,,分别代表着元素原生元素,回调函数

系列文章

React Fiber源码分析 第一篇
React Fiber源码分析 第二篇(同步模式)
React Fiber源码分析 第三篇(异步状态)
React Fiber源码分析 第四篇(归纳总结)

前言

React Fiber是React在V16版本中的大更新,利用了闲余时间看了一些源码,做个小记录~

流程图

源码分析

先由babel编译, 调用reactDOM.render,入参为element, container, callback, 打印出来可以看到element,container,callback分别代表着react元素、DOM原生元素,回调函数

1.render实际上调用的是legacyRenderSubtreeIntoContainer函数

render: function (element, container, callback) {
  return legacyRenderSubtreeIntoContainer(null, element, container, false, callback);
}

2.legacyRenderSubtreeIntoContainer 这个函数, 实际上是初始化了root, 并调用了root.render方法, 而root是由legacyCreateRootFromDOMContainer函数返回的

function legacyRenderSubtreeIntoContainer(parentComponent, children, container, forceHydrate, callback) {
  var root = container._reactRootContainer;
  if (!root) {
    // 初始化root
    root = container._reactRootContainer = legacyCreateRootFromDOMContainer(container, forceHydrate);// Initial mount should not be batched.
    unbatchedUpdates(function () {
      if (parentComponent != null) {
        root.legacy_renderSubtreeIntoContainer(parentComponent, children, callback);
      } else {
        // 调用root的render方法
        root.render(children, callback);
      }
    });
  } else {
    ......
  }
}

3.从代码中看出, legacyCreateRootFromDOMContainer执行了两个操作, 一个是清除掉所有的子元素, 另外一个则是返回了一个 ReactRoot实例, 这里需要注意一点, root默认是同步更新的, 即isAsync 默认为false

function legacyCreateRootFromDOMContainer(container, forceHydrate) {
  ...// 清除所有子元素
  if (!shouldHydrate) {
    var warned = false;
    var rootSibling = void 0;
    while (rootSibling = container.lastChild) {
      {
        if (!warned && rootSibling.nodeType === ELEMENT_NODE && rootSibling.hasAttribute(ROOT_ATTRIBUTE_NAME)) {
          warned = true;
        }
      }
      container.removeChild(rootSibling);
    }
  }// 默认为同步状态
  var isAsync = false;
  return new ReactRoot(container, isAsync, shouldHydrate);
}

4.从ReactRoot中, 我们把createContainer返回值赋给了 实例的_internalRoot, 往下看createContainer

function ReactRoot(container, isAsync, hydrate) {
  var root = createContainer(container, isAsync, hydrate);
  this._internalRoot = root;
}

5.从createContainer看出, createContainer实际上是直接返回了createFiberRoot, 而createFiberRoot则是通过createHostRootFiber函数的返回值uninitializedFiber,并将其赋值在root对象的current上, 这里需要注意一个点就是,uninitializedFiber的stateNode的值是root, 即他们互相引用

function createContainer(containerInfo, isAsync, hydrate) {
  return createFiberRoot(containerInfo, isAsync, hydrate);
}
function createFiberRoot(containerInfo, isAsync, hydrate) {
  // 创建hostRoot并赋值给uninitiallizedFiber
  var uninitializedFiber = createHostRootFiber(isAsync);
  // 互相引用
  var root = void 0;
  root = {
      current: uninitializedFiber,
      ...
  };
 uninitializedFiber.stateNode = root; 

6.最后是返回了一个fiberNode的实例, 在这里我们可以看到mode这个字段, 由于在一开始就将isAsync初始化为false, 所以mode实际上就代表了同步

在这里, 整理一下各个实例的关系,

root为ReactRoot实例

root._internalRoot 即为fiberRoot实例

root._internalRoot.current即为Fiber实例

root._internalRoot.current.stateNode = root._internalRoot

function createHostRootFiber(isAsync) {
  var mode = isAsync ? AsyncMode | StrictMode : NoContext;
  return createFiber(HostRoot, null, null, mode);
}
var createFiber = function (tag, pendingProps, key, mode) {
  return new FiberNode(tag, pendingProps, key, mode);
};
function FiberNode(tag, pendingProps, key, mode) {
  // Instance
  this.tag = tag;
  this.key = key;
  this.type = null;
  this.stateNode = null;

  // Fiber
  this.return = null;
  this.child = null;
  this.sibling = null;
  this.index = 0;

  ...
}

7.初始化完成, 接下来就是root.render执行了, 在这里, 先暂时忽略ReactWork, 把work._onCommit当成一个回调函数即可, 可以看到, root即FiberRoot实例被当成参数传入了updateContsainer里面, 往下看updateContainer

ReactRoot.prototype.render = function (children, callback) {
  var root = this._internalRoot;
  var work = new ReactWork();
  callback = callback === undefined ? null : callback;
  if (callback !== null) {
    work.then(callback);
  }
  updateContainer(children, root, null, work._onCommit);
  return work;
};

8.updateContsainer里面使用了 currentTimeexpirationTime,

currentTime是用来计算expirationTime,

expirationTime代表着优先级, 留在后续分析,

这里我们知道是同步更新 即 expirationTime = 1. 紧接着调用了updateContainerAtExpirationTime

function updateContainer(element, container, parentComponent, callback) {
  var current$$1 = container.current;
  var currentTime = requestCurrentTime();
  var expirationTime = computeExpirationForFiber(currentTime, current$$1);
  return updateContainerAtExpirationTime(element, container, parentComponent, expirationTime, callback);
}

9.updateContainerAtExpirationTime将current(即Fiber实例)提取出来, 并作为参数传入调用scheduleRootUpdate

function updateContainerAtExpirationTime(element, container, parentComponent, expirationTime, callback) {
  // TODO: If this is a nested container, this won"t be the root.
  var current$$1 = container.current;
  ...
  return scheduleRootUpdate(current$$1, element, expirationTime, callback);
}

到了这里告一段落, scheduleRootUpdate接下来就是React新版本异步渲染的核心了, 留在下一篇继续解读

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/108919.html

相关文章

  • React Fiber源码分析 第四篇(归纳总结)

    摘要:为什么网页性能会变高要回答这个问题,需要回头看是单线程的知识点。在分析的过程中,发现了的源码中使用了很多链式结构,回调链,任务链等,这个主要是为了增删时性能比较高 系列文章 React Fiber源码分析 第一篇 React Fiber源码分析 第二篇(同步模式) React Fiber源码分析 第三篇(异步状态) React Fiber源码分析 第四篇(归纳总结) 前言 Rea...

    jsdt 评论0 收藏0
  • React Fiber源码分析 第三篇(异步状态)

    摘要:系列文章源码分析第一篇源码分析第二篇同步模式源码分析第三篇异步状态源码分析第四篇归纳总结前言是在版本中的大更新,利用了闲余时间看了一些源码,做个小记录流程图源码分析调用时,会调用的方法,同时将新的作为参数传进会先调用获取一个维护两个时间一个 系列文章 React Fiber源码分析 第一篇 React Fiber源码分析 第二篇(同步模式) React Fiber源码分析 第三篇(...

    worldligang 评论0 收藏0
  • 浅谈React Fiber

    摘要:因为版本将真正废弃这三生命周期到目前为止,的渲染机制遵循同步渲染首次渲染,更新时更新时卸载时期间每个周期函数各司其职,输入输出都是可预测,一路下来很顺畅。通过进一步观察可以发现,预废弃的三个生命周期函数都发生在虚拟的构建期间,也就是之前。 showImg(https://segmentfault.com/img/bVbweoj?w=559&h=300); 背景 前段时间准备前端招聘事项...

    izhuhaodev 评论0 收藏0
  • React Fiber源码分析 第二篇(同步模式)

    摘要:函数主要执行两个操作,一个是判断当前是否还有任务,如果没有,则从链中移除。 系列文章 React Fiber源码分析 第一篇 React Fiber源码分析 第二篇(同步模式) React Fiber源码分析 第三篇(异步状态) React Fiber源码分析 第四篇(归纳总结) 前言 React Fiber是React在V16版本中的大更新,利用了闲余时间看了一些源码,做个小记...

    OBKoro1 评论0 收藏0
  • Deep In React 之详谈 React 16 Diff 策略(二)

    摘要:对于同一层级的一组子节点,它们可以通过唯一进行区分。基于以上三个前提策略,分别对以及进行算法优化。链表的每一个节点是,而不是在之前的虚拟节点。是当前层的第一个节点。再次提醒,是的一层。 文章首发于个人博客 这是我 Deep In React 系列的第二篇文章,如果还没有读过的强烈建议你先读第一篇:详谈 React Fiber 架构(1)。 前言 我相信在看这篇文章的读者一般都已经了解...

    NSFish 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<