React Fiber源码分析 第一篇

10次阅读

共计 4122 个字符,预计需要花费 11 分钟才能阅读完成。

前言
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 里面使用了 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);
}
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 新版本异步渲染的核心了,留在下一篇继续解读

正文完
 0