React Fiber源码分析 第一篇
React Fiber源码分析 第二篇(同步模式)
React Fiber源码分析 第三篇(异步状态)
React Fiber源码分析 第四篇(概括总结)node
React Fiber是React在V16版本中的大更新,利用了闲余时间看了一些源码,作个小记录~react
先由babel编译, 调用reactDOM.render,入参为element, container, callback, 打印出来能够看到element,container,callback分别表明着react元素、DOM原生元素,回调函数
bash
1.render实际上调用的是legacyRenderSubtreeIntoContainer函数babel
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, 即他们互相引用post
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实际上就表明了同步ui
在这里, 整理一下各个实例的关系,this
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新版本异步渲染的核心了, 留在下一篇继续解读