准备工作
如果是使用vscode的大佬,建议下载插件bookmarks 、better Comments。
通过 Bookmarks 去添加标签做快速跳转。
配置可以参照文章中的,只是下载的文件还是走上面链接的去下载
阅读源码切记要盯紧目标,放弃分支
从入口开始
最简单的例子:
ReactDOM.render(
React.createElement(ForRender,{val:100}),
document.getElementById('root')
)
源码部分:
第一步 render 方法:
render: function (element, container, callback) {
// element = React.createElement(ForRender,{val:100})
// 执行出来的话是
var element = {
// This tag allows us to uniquely identify this as a React Element
$$typeof: REACT_ELEMENT_TYPE,
// Built-in properties that belong on the element
type: type,
key: key,
ref: ref,
props: props,
// Record the component responsible for creating this element.
_owner: owner
};
// container = document.getElementById('root')
return legacyRenderSubtreeIntoContainer(null, element, container, false, callback);
},
第二步 legacyRenderSubtreeIntoContainer方法:
// legacyRenderSubtreeIntoContainer 渲染子节点到容器内
function legacyRenderSubtreeIntoContainer(parentComponent, children, container, forceHydrate, callback) {
var root = container._reactRootContainer;
// root 绝对是undefined的,因为默认的div是不可能有_reactRootContainer的
if(!root){
// 基于dom节点去创建根节点
root = container._reactRootContainer = legacyCreateRootFromDOMContainer(container, forceHydrate);
// 进入此函数时,root节点已经初始化完毕
// Initial mount should not be batched.
unbatchedUpdates(function () {
// parentComponent 在render 传过来时一定为空
if (parentComponent != null) {
root.legacy_renderSubtreeIntoContainer(parentComponent, children, callback);
} else {
root.render(children, callback);
}
});
}
}
第三步 legacyCreateRootFromDOMContainer 方法:
function legacyCreateRootFromDOMContainer(container, forceHydrate) {
// 前面唯一需要注意的就是这句
container.removeChild(rootSibling);
删除root根节点的所有子节点
...
var isConcurrent = false;
return new ReactRoot(container, isConcurrent, shouldHydrate);
}
第四步 ReactRoot 方法:
// ReactRoot 是一个构造函数,所以晚点在下面去分析原型挂载的render方法
function ReactRoot(container, isConcurrent, hydrate) {
// 传入的参数是: div false false
var root = createContainer(container, isConcurrent, hydrate);
// createContainer 创建一个容器
this._internalRoot = root;
}
第五步 createContainer 方法:
function createContainer(containerInfo, isConcurrent, hydrate) {
// 创建一个fiberRoot
return createFiberRoot(containerInfo, isConcurrent, hydrate);
}
第六步 createFiberRoot 方法:
// 从方法来看就是创建一个root对象,里面有一堆属性。
function createFiberRoot(containerInfo, isConcurrent, hydrate) {
// Cyclic construction. This cheats the type system right now because
// stateNode is any.
var uninitializedFiber = createHostRootFiber(isConcurrent);
var root = void 0;
if (enableSchedulerTracing) {
root = {
current: uninitializedFiber,
containerInfo: containerInfo,
pendingChildren: null,
earliestPendingTime: NoWork,
latestPendingTime: NoWork,
earliestSuspendedTime: NoWork,
latestSuspendedTime: NoWork,
latestPingedTime: NoWork,
pingCache: null,
didError: false,
pendingCommitExpirationTime: NoWork,
finishedWork: null,
timeoutHandle: noTimeout,
context: null,
pendingContext: null,
hydrate: hydrate,
nextExpirationTimeToWorkOn: NoWork,
expirationTime: NoWork,
firstBatch: null,
nextScheduledRoot: null,
interactionThreadID: unstable_getThreadID(),
memoizedInteractions: new Set(),
pendingInteractionMap: new Map()
};
} else {
root = {
current: uninitializedFiber,
containerInfo: containerInfo,
pendingChildren: null,
pingCache: null,
earliestPendingTime: NoWork,
latestPendingTime: NoWork,
earliestSuspendedTime: NoWork,
latestSuspendedTime: NoWork,
latestPingedTime: NoWork,
didError: false,
pendingCommitExpirationTime: NoWork,
finishedWork: null,
timeoutHandle: noTimeout,
context: null,
pendingContext: null,
hydrate: hydrate,
nextExpirationTimeToWorkOn: NoWork,
expirationTime: NoWork,
firstBatch: null,
nextScheduledRoot: null
};
}
uninitializedFiber.stateNode = root;
return root;
}
fiberRoot 留到后面再分析里面的每一项是啥东西。 感兴趣可以看下fiberRoot数据结构
第七步 ReactRoot.prototype.render
ReactRoot.prototype.render = function (children, callback) {
var root = this._internalRoot;
....
updateContainer(children, root, null, work._onCommit);
return work;
};
....后续补充,
expirationTime理解
expirationTime 到期时间,用于描述任务队列的到期时间。expirationTime的计算有点难理解,
首先第一个理解什么是 unstable_now ,通过源码定位到
var localDate = Date;
if (hasNativePerformanceNow) {
var Performance = performance;
getCurrentTime = function() {
return Performance.now();
};
} else {
getCurrentTime = function() {
return localDate.now();
};
}
所以现在就需要来理解一下什么是performance.now()了。performance.now()简单来说就是从网页打开到你打印这个值的毫秒时间。不是从1970年开始的时间戳。
未完待续...