博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
React Fiber源码分析 第一篇
阅读量:6174 次
发布时间:2019-06-21

本文共 4685 字,大约阅读时间需要 15 分钟。

系列文章

前言

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

流程图

1098644-20181106205304321-1267896425.png

源码分析

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

image

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新版本异步渲染的核心了, 留在下一篇继续解读

转载地址:http://waqba.baihongyu.com/

你可能感兴趣的文章
[noip模拟20170921]模版题
查看>>
获取ip
查看>>
Spring Shell简单应用
查看>>
移动app可开发的意见于分析
查看>>
周总结7
查看>>
类似OutLook布局的开源控件XPanderControls
查看>>
Web前端工程师成长之路——知识汇总
查看>>
[2018-9-4T2]探索黑暗dark
查看>>
【学术信息】中科院2019年学术期刊分区-综合性期刊
查看>>
ShareObject离线存储相关
查看>>
C++ XML
查看>>
windows批处理 打开exe后关闭cmd
查看>>
Linux 安装中文包
查看>>
谷物大脑
查看>>
访问控制-禁止php解析、user_agent,PHP相关配置
查看>>
AgileEAS.NET之系统架构
查看>>
python3.5里的正则表达式
查看>>
Exchange server 2013 SP1 客户端会议室邮箱自动回复延迟
查看>>
nginx反向代理缓存服务器构建
查看>>
RHEL6 搭建LVS/DR 负载均衡集群 案例
查看>>