React Fiber源码分析 第一篇

发布日期:2019-03-31

 先附上流程图一张

 

 

 

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

render实际上调用的是 legacyRenderSubtreeIntoContainer函数

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

 

 

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 { ...... }}

 

从代码中看出, 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)}

 

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

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

 

createContainer看出, createContainer实际上是直接返回了createFiberRootcreateFiberRoot则是通过createHostRootFiber函数的返回值uninitializedFiber,并将其赋值在root对象的current上, 这里需要注意一个点就是,uninitializedFiberstateNode的值是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

 

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

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

 rootReactRoot实例,

 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 ...}

 

初始化完成, 接下来就是root.render执行了, 在这里, 先暂时忽略ReactWork 把work._onCommit当成一个回调函数即可, 可以看到, rootFiberRoot实例被当成参数传入了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}

 

updateContsainer里面使用了 currentTime 和 expirationTime 

 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)}

 

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