前言:为了搞清楚react到底是个什么样的“框架”以及它的内部机制,因此开始阅读react源码。在阅读源码的时候,为了梳理流程,根据自己的理解以及网上的一些资料做了一些(大致流程的)笔记。笔记是当时的理解,写的时候,仍然有很多不理解的地方待后续完善。而写出来的部分,可能会有很多理解不到位甚至是错误的地方,一旦有新的理解或者发现了错误,会补充与修正。
react源码版本:16.8.6
import ReactDOM from 'react-dom';
ReactDOM.render( , document.getElementById('root));
代码路径:packages/react-dom/src/client/ReactDOM.js
const ReactDOM: Object = {
...
render(
element: React$Element<any>, // React Element,也就是上面的
container: DOMContainer, // 一个dom节点,也就是上面的root
callback: ?Function, // 回调函数,可不传
) {
...
return legacyRenderSubtreeIntoContainer(
null,
element,
container,
false,
callback,
);
},
...
可以看到这里调用了legacyRenderSubtreeIntoContainer函数并返回,然后找到该函数源码。
代码路径:packages/react-dom/src/client/ReactDOM.js
// 将子组件树渲染进container中
function legacyRenderSubtreeIntoContainer(
parentComponent: ?React$Component<any, any>, // 父组件,这里传入的是null
children: ReactNodeList, // 子节点,这里是上面传入的
container: DOMContainer, // 这里是root节点
forceHydrate: boolean, // 是否进行组合,render传入的是false
callback: ?Function, // 上面的回调函数
) {
...
// TODO: Without `any` type, Flow says "Property cannot be accessed on any
// member of intersection type." Whyyyyyy.
// 这里是初次渲染,container上没有_reactRootContainer属性,root为false
let root: Root = (container._reactRootContainer: any);
if (!root) {
// 初次挂载
root = container._reactRootContainer = legacyCreateRootFromDOMContainer(
container,
forceHydrate,
);
if (typeof callback === 'function') {
const originalCallback = callback;
callback = function() {
const instance = getPublicRootInstance(root._internalRoot);
originalCallback.call(instance);
};
}
// Initial mount should not be batched.
unbatchedUpdates(() => {
if (parentComponent != null) {
root.legacy_renderSubtreeIntoContainer(
parentComponent,
children,
callback,
);
} else {
root.render(children, callback);
}
});
} else {
...
}
return getPublicRootInstance(root._internalRoot);
}
可以看到,legacyRenderSubtreeIntoContainer函数做了几件事:
代码路径:packages/react-dom/src/client/ReactDOM.js
// 清除container下的内容并获取返回ReactRoot赋值给上一层的root
function legacyCreateRootFromDOMContainer(
container: DOMContainer, // root节点
forceHydrate: boolean, // false
): Root {
// 这里为false
const shouldHydrate =
forceHydrate || shouldHydrateDueToLegacyHeuristic(container);
// 进入判断,清除掉container下的所有内容
if (!shouldHydrate) {
let warned = false;
let rootSibling;
while ((rootSibling = container.lastChild)) {
...
// 做了一些判断与提示的工作
...
// 看函数名字可以知道,清除root下的内容
container.removeChild(rootSibling);
}
}
...
// 做了一些判断与提示的工作
...
// 默认情况下root非异步
const isConcurrent = false;
return new ReactRoot(container, isConcurrent, shouldHydrate);
}
// ReactRoot构造函数
function ReactRoot(
container: DOMContainer, // root节点
isConcurrent: boolean, // false
hydrate: boolean, // false
) {
const root = createContainer(container, isConcurrent, hydrate);
this._internalRoot = root;
}
// ReactRoot原型的一些方法(简化了下)
ReactRoot.prototype.render = function(
children: ReactNodeList,
callback: ?() => mixed,
): Work {
const root = this._internalRoot;
const work = new ReactWork();
callback = callback === undefined ? null : callback;
...
if (callback !== null) {
work.then(callback);
}
updateContainer(children, root, null, work._onCommit);
return work;
};
ReactRoot.prototype.unmount = function(callback: ?() => mixed): Work {
...
};
ReactRoot.prototype.legacy_renderSubtreeIntoContainer = function(
parentComponent: ?React$Component<any, any>,
children: ReactNodeList,
callback: ?() => mixed,
): Work {
...
};
ReactRoot.prototype.createBatch = function(): Batch {
...
};
到这里可以得出一个结论,获取的ReactRoot是一个对象,包含以下几个属性:
_internalRoot
render
unmount
legacy_renderSubtreeIntoContainer
createBatch
但目前首先要关心的是_internalRoot,这个是下面的几个步骤要用到的,那就必须看一下createContainer方法;createContainer方法并不是在当前文件中定义,而是最终调用了ReactFiberRoot.js文件内的createFiberRoot方法;
代码路径:packages/react-reconciler/src/ReactFiberRoot.js
export function createFiberRoot(
containerInfo: any, // container,这里是最初从render函数传进来的root dom节点
isConcurrent: boolean, // false
hydrate: boolean, //false
): FiberRoot {
const root: FiberRoot = (new FiberRootNode(containerInfo, hydrate): any);
// Cyclic construction. This cheats the type system right now because
// stateNode is any.
const uninitializedFiber = createHostRootFiber(isConcurrent);
root.current = uninitializedFiber;
uninitializedFiber.stateNode = root;
return root;
}
// FiberRootNode构造函数
function FiberRootNode(containerInfo, hydrate) {
this.current = null;
this.containerInfo = containerInfo;
this.pendingChildren = null;
this.pingCache = null;
this.pendingCommitExpirationTime = NoWork;
this.finishedWork = null;
this.timeoutHandle = noTimeout;
this.context = null;
this.pendingContext = null;
this.hydrate = hydrate;
this.firstBatch = null;
this.callbackNode = null;
this.callbackExpirationTime = NoWork;
this.firstPendingTime = NoWork;
this.lastPendingTime = NoWork;
this.pingTime = NoWork;
if (enableSchedulerTracing) {
this.interactionThreadID = unstable_getThreadID();
this.memoizedInteractions = new Set();
this.pendingInteractionMap = new Map();
}
}
由上面的代码可以看出来,_internalRoot其实就是一个包含众多属性的FiberRoot实例对象。它的current属性被赋值为createHostRootFiber的返回值。
createHostRootFiber其实是创建了一个Fiber对象,但这个Fiber的初始tag被设置为了HostRoot(代表这是一个宿主根,不能被其他节点嵌套),因此被称作RootFiber(与FiberRoot是两个概念)。
于是可以列出ReactRoot的结构了:
{
_internalRoot: { // FiberRoot实例对象
...
current: { //RootFiber实例对象
...
stateNode //FiberRoot实例对象,也就是它的上上一层,
...
}
...
},
render: function() {}
unmount: function() {}
legacy_renderSubtreeIntoContainer: function() {}
createBatch: function() {}
}
也就是说:
FiberRoot.current = RootFiber;
RootFiber.stateNode = FiberRoot;
/////////////////////
React源码解析笔记—调度更新(一)