点击这里进入react原理专栏
这篇文章来看一下react
应用的入口:ReactDOM.render
的流程。ReactDOM.render
主要做了三件事:创建整个应用的根fiber
节点:fiberRoot
,合成事件的处理以及挂载应用。
render
方法会调用legacyRenderSubtreeIntoContainer
方法
function legacyRenderSubtreeIntoContainer(parentComponent, children, container, forceHydrate, callback) {
var root = container._reactRootContainer;
var fiberRoot;
if (!root) {
// 初次挂载,创建根节点
root = container._reactRootContainer = legacyCreateRootFromDOMContainer(container, forceHydrate);
fiberRoot = root._internalRoot;
// 应用的挂载
unbatchedUpdates(function () {
updateContainer(children, fiberRoot, parentComponent, callback);
});
} else {
// 。。。
}
return getPublicRootInstance(fiberRoot);
}
legacyCreateRootFromDOMContainer
方法源码如下
function legacyCreateRootFromDOMContainer(container, forceHydrate) {
if (!shouldHydrate) {
var warned = false;
var rootSibling;
while (rootSibling = container.lastChild) {
{
if (!warned && rootSibling.nodeType === ELEMENT_NODE && rootSibling.hasAttribute(ROOT_ATTRIBUTE_NAME)) {
warned = true;
error('render(): Target node has markup rendered by React, but there ' + 'are unrelated nodes as well. This is most commonly caused by ' + 'white-space inserted around server-rendered markup.');
}
}
// 清空root节点内的dom元素
container.removeChild(rootSibling);
}
}
// 。。。
return createLegacyRoot(container, shouldHydrate ? {
hydrate: true
} : undefined);
}
这个方法会清空root
元素内的dom节点,之后经过一系列方法调用,来到了createRootImpl
function createRootImpl(container, tag, options) {
// ...
var root = createContainer(container, tag, hydrate);
{
var rootContainerElement = container.nodeType === COMMENT_NODE ? container.parentNode : container;
listenToAllSupportedEvents(rootContainerElement);
}
// ...
return root;
}
这个方法主要干了两件事:创建fiberRoot
,以及合成事件的处理。分别对应createContainer
方法和listenToAllSupportedEvents
方法。合成事件的原理会有文章进行介绍。
至此,legacyCreateRootFromDOMContainer
方法执行完毕,接下来开始挂载整个应用,进入updateContainer
方法(unbatchedUpdates
先略过)。updateContainer
方法会调用scheduleUpdateOnFiber
方法,开始进行更新(这个方法就是更新react
应用的入口)。
下面看scheduleUpdateOnFiber
方法的这段逻辑:
if (
(executionContext & LegacyUnbatchedContext) !== NoContext &&
(executionContext & (RenderContext | CommitContext)) === NoContext) {
// ReactDOM.render进入这里
schedulePendingInteractions(root, lane);
performSyncWorkOnRoot(root);
} else {
// 后续更新进入这里
ensureRootIsScheduled(root, eventTime);
schedulePendingInteractions(root, lane);
if (executionContext === NoContext) {
resetRenderTimer();
flushSyncCallbackQueue();
}
}
现在再看unbatchedUpdates
方法
function unbatchedUpdates(fn, a) {
var prevExecutionContext = executionContext;
executionContext &= ~BatchedContext;
executionContext |= LegacyUnbatchedContext;
try {
return fn(a);
} finally {
executionContext = prevExecutionContext;
// ...
}
}
unbatchedUpdates
方法执行了executionContext |= LegacyUnbatchedContext
,因此之后到unbatchedUpdates
方法中,executionContext & LegacyUnbatchedContext) !== NoContext
为true
,而RenderContext
和CommitContext
时在render
阶段和commit
阶段被设置的,因此executionContext & (RenderContext | CommitContext)) === NoContext
为true
。之后进入了performSyncWorkOnRoot
(后续更新的过程也会调用performSyncWorkOnRoot
,只是调用方式不同)。
进入performSyncWorkOnRoot
中有两个重要的方法调用:renderRootSync
和commitRoot
,分别对应render
阶段和commit
阶段的入口。这些内容会有专门的文章进行讲解。
本文讲解了整个react
的入口ReactDOM.render
的部分流程,这里提到了合成事件,render
和commit
阶段,这些内容都会有相应的文章进行讲解,敬请期待!!