Open Foveluy opened 6 years ago
export type TypeOfWork = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10;
export const IndeterminateComponent = 0; // 尚不知是类组件还是函数式组件
export const FunctionalComponent = 1; // 函数式组件
export const ClassComponent = 2; // Class类组件
export const HostRoot = 3; // 组件树根组件,可以嵌套
export const HostPortal = 4; // 子树. Could be an entry point to a different renderer.
export const HostComponent = 5; // 标准组件,如地div, span等
export const HostText = 6; // 文本
export const CallComponent = 7; // 组件调用
export const CallHandlerPhase = 8; // 调用组件方法
export const ReturnComponent = 9; // placeholder(占位符)
export const Fragment = 10; // 片段
// A Fiber is work on a Component that needs to be done or was done. There can
// be more than one per component.
var debugCounter = void 0;
{
debugCounter = 1;
}
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;
this.ref = null;
this.pendingProps = pendingProps;
this.memoizedProps = null;
this.updateQueue = null;
this.memoizedState = null;
this.mode = mode;
// Effects
this.effectTag = NoEffect;
this.nextEffect = null;
this.firstEffect = null;
this.lastEffect = null;
this.expirationTime = NoWork;
this.alternate = null;
{
this._debugID = debugCounter++;
this._debugSource = null;
this._debugOwner = null;
this._debugIsCurrentlyTiming = false;
if (!hasBadMapPolyfill && typeof Object.preventExtensions === 'function') {
Object.preventExtensions(this);
}
}
}
render
|
v
legacyCreateRootFromDOMContainer
//这个函数会给 root container 创建一个 Root.fiber 和是一个特殊的对象
function legacyCreateRootFromDOMContainer(container, forceHydrate) {
var shouldHydrate = forceHydrate || shouldHydrateDueToLegacyHeuristic(container);
// First clear any existing content.
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;
warning(false, '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.');
}
}
container.removeChild(rootSibling);
}
}
{
if (shouldHydrate && !forceHydrate && !warnedAboutHydrateAPI) {
warnedAboutHydrateAPI = true;
lowPriorityWarning$1(false, 'render(): Calling ReactDOM.render() to hydrate server-rendered markup ' + 'will stop working in React v17. Replace the ReactDOM.render() call ' + 'with ReactDOM.hydrate() if you want React to attach to the server HTML.');
}
}
// Legacy roots are not async by default.
var isAsync = false;
return new ReactRoot(container, isAsync, shouldHydrate);
}
// 那么 fiber root 的结构是
function createFiberRoot(containerInfo, isAsync, hydrate) {
// Cyclic construction. This cheats the type system right now because
// stateNode is any.
var uninitializedFiber = createHostRootFiber(isAsync);
var root = {
current: uninitializedFiber,
containerInfo: containerInfo,
pendingChildren: null,
pendingCommitExpirationTime: NoWork,
finishedWork: null,
context: null,
pendingContext: null,
hydrate: hydrate,
remainingExpirationTime: NoWork,
firstBatch: null,
nextScheduledRoot: null
};
uninitializedFiber.stateNode = root;
return root;
}
|
|
v
//首次渲染不会执行批量更新
DOMRenderer.unbatchedUpdates
|
v
updateContainer
|
v
//获取context
var context = getContextForSubtree(parentComponent);
if (container.context === null) {
container.context = context;
} else {
container.pendingContext = context;
}
|
v
scheduleRootUpdate()
//伴随着以下数据结构
var update = {
expirationTime: expirationTime,
partialState: { element: element },
callback: callback,
isReplace: false,
isForced: false,
capturedValue: null,
next: null
};
|
v
insertUpdateIntoFiber()
// 这个函数做了一件事情
// setState 和 render 的时候,都会创建一个 update,这个方法就是把这个 update 放入队列中,这个队列是一个链表
|
v
//是执行虚拟DOM(fiber树)的更新
scheduleWorkImpl() --->scheduleWork是他的包囊方法,其实没啥用
|
v
// Add this root to the root schedule.
requestWork(root, expirationTime);
|
v
// 调用 performSyncWork()
if (expirationTime === Sync) {
performSyncWork();
} else {
scheduleCallbackWithExpiration(expirationTime);
}
|
v
// performWork(Sync, false, null);
performWork(Sync, false, null);
|
v
performWorkOnRoot()
|
v
//往下走到达
renderRoot(root, expirationTime, isAsync)
//再往下就是一个关键的方法,这个方法中,我们通过现有的 Fiber 构建出
// WorkInProgress tree,WorkInProgress tree 就是新的 Fiber
// 对其进行比较
function createWorkInProgress(current, pendingProps, expirationTime)
// This is used to create an alternate fiber to do work on.
|
v
workloop
|
|
v
performUnitOfWork(workInProgress)
|
|
v
//这个方法,返回下一个要处理的 Fiber
function beginWork(current, workInProgress, renderExpirationTime)
// 这个函数是一个 switch tag.
switch (workInProgress.tag) {
case IndeterminateComponent:
return mountIndeterminateComponent(current, workInProgress, renderExpirationTime);
case FunctionalComponent:
return updateFunctionalComponent(current, workInProgress);
case ClassComponent:
return updateClassComponent(current, workInProgress, renderExpirationTime);
case HostRoot:
return updateHostRoot(current, workInProgress, renderExpirationTime);
case HostComponent:
return updateHostComponent(current, workInProgress, renderExpirationTime);
case HostText:
return updateHostText(current, workInProgress);
case CallHandlerPhase:
// This is a restart. Reset the tag to the initial phase.
workInProgress.tag = CallComponent;
// Intentionally fall through since this is now the same.
case CallComponent:
return updateCallComponent(current, workInProgress, renderExpirationTime);
case ReturnComponent:
// A return component is just a placeholder, we can just run through the
// next one immediately.
return null;
case HostPortal:
return updatePortalComponent(current, workInProgress, renderExpirationTime);
case ForwardRef:
return updateForwardRef(current, workInProgress);
case Fragment:
return updateFragment(current, workInProgress);
case Mode:
return updateMode(current, workInProgress);
case ContextProvider:
return updateContextProvider(current, workInProgress, renderExpirationTime);
case ContextConsumer:
return updateContextConsumer(current, workInProgress, renderExpirationTime);
default:
invariant(false, 'Unknown unit of work tag. This error is likely caused by a bug in React. Please file an issue.');
}
}
|
|
v
workInProgress.tag 是什么?
https://github.com/facebook/react/blob/master/packages/shared/ReactTypeOfWork.js
|
|
v
//核心方法
function reconcileChildren(current, workInProgress, nextChildren)
|
|
v
// We've completed the root. Commit it.
completeRoot(root, finishedWork, expirationTime);
|
v
// Commit the root.
root.finishedWork = null;
root.remainingExpirationTime = commitRoot(finishedWork);
|
v
//commitRoot() 巨复杂
|
v
commitLifeCycles()
//是一个大循环,拿到 effect list 进行循环
while (nextEffect !== null) {
var effectTag = nextEffect.effectTag;
if (effectTag & (Update | Callback)) {
recordEffect();
var current = nextEffect.alternate;
commitLifeCycles(finishedRoot, current, nextEffect, currentTime, committedExpirationTime);
}
if (effectTag & ErrLog) {
commitErrorLogging(nextEffect, onUncaughtError);
}
if (effectTag & Ref) {
recordEffect();
commitAttachRef(nextEffect);
}
var next = nextEffect.nextEffect;
// Ensure that we clean these up so that we don't accidentally keep them.
// I'm not actually sure this matters because we can't reset firstEffect
// and lastEffect since they're on every node, not just the effectful
// ones. So we have to clean everything as we reuse nodes anyway.
nextEffect.nextEffect = null;
// Ensure that we reset the effectTag here so that we can rely on effect
// tags to reason about the current life-cycle.
nextEffect = next;
}
|
v