原文:Inside Fiber: in-depth overview of the new reconciliation algorithm in Reactreact
译文:React Fiber 那些事: 深刻解析新的协调算法算法
上面提供了两篇很是优秀的介绍React协调算法的文章,建议读者先看原文或者译文,看完一遍以后若是没有太深的印象,那么再从本文提供的角度去思考问题。segmentfault
在 《剖析React内部运行机制-「译」React组件、元素和实例》 这篇文章中咱们知道:浏览器
那么如何将应用程序中众多的 “React元素” 组装成 树 就是协调算法核心工做的一部分。数据结构
注意: 浏览器只是React能够渲染的“渲染环境”之一,其余主要的目标是经过React native实现的iOS和Android视图(这就是为何“虚拟DOM”有点用词不当)。在 《剖析React内部运行机制-「译」React Fiber 架构》 这篇文章的 “协调与渲染” 部分有更加详细的介绍。架构
React Fiber,其构造函数为:ide
function FiberNode(tag, pendingProps, key, mode) {
// 此处属性用于生成DOM节点实例
this.tag = tag; // 用于标识组件的类型,好比class组件、function组件、宿主组件等
this.key = key;
this.elementType = null;
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.dependencies = null;
this.mode = mode;
// 此处属性用于反作用(的调用,好比生命周期函数等)
this.effectTag = NoEffect;
this.nextEffect = null;
this.firstEffect = null;
this.lastEffect = null;
this.expirationTime = NoWork;
this.childExpirationTime = NoWork;
this.alternate = null;
if (enableProfilerTimer) {
// 下面的操做是为了不v8性能问题
this.actualDuration = Number.NaN;
this.actualStartTime = Number.NaN;
this.selfBaseDuration = Number.NaN;
this.treeBaseDuration = Number.NaN;
this.actualDuration = 0;
this.actualStartTime = -1;
this.selfBaseDuration = 0;
this.treeBaseDuration = 0;
}
{
this._debugID = debugCounter++;
this._debugSource = null;
this._debugOwner = null;
this._debugIsCurrentlyTiming = false;
this._debugNeedsRemount = false;
this._debugHookTypes = null;
if (!hasBadMapPolyfill && typeof Object.preventExtensions === 'function') {
Object.preventExtensions(this);
}
}
}
复制代码
固然,React Fiber的属性用的最多的仍是前半部分。其更加详细做用在《剖析React内部运行机制-「译」React Fiber 架构》 这篇文章中有介绍。函数
一、协调算法入口函数-renderRootoop
function renderRoot(root, expirationTime, isSync) {
...
// 该方法内部会建立workInProgress,并暴露到外层(即renderRoot)做用域
prepareFreshStack(root, expirationTime);
...
// 开始执行工做循环
if (isSync) {
workLoopSync();
} else {
workLoop();
}
...
// 检查工做循环结束后的workInProgress状态
switch (workInProgressRootExitStatus) {
...
case RootCompleted:
return commitRoot.bind(null, root);
}
}
复制代码
二、工做循环/组件解析-workLoopSyncpost
function workLoopSync() {
while (workInProgress !== null) {
workInProgress = performUnitOfWork(workInProgress);
}
}
复制代码
三、执行工做单元-performUnitOfWork
function performUnitOfWork(unitOfWork) {
var current$$1 = unitOfWork.alternate;
...
var next = void 0;
next = beginWork$$1(current$$1, unitOfWork, renderExpirationTime);
...
return next;
}
复制代码
四、开始工做--beginWork$$1(其实是执行的是下面beginWork$1)
function beginWork$1(current$$1, workInProgress, renderExpirationTime) {
...
// 这里根据当前组件的类型分别返回不一样的内容
switch (workInProgress.tag) {
...
case FunctionComponent:
return updateFunctionComponent(current$$1, workInProgress, _Component, resolvedProps, renderExpirationTime);
case ClassComponent:
return updateClassComponent(current$$1, workInProgress, _Component2, _resolvedProps, renderExpirationTime);
case HostRoot:
return updateHostRoot(current$$1, workInProgress, renderExpirationTime);
case HostComponent:
return updateHostComponent(current$$1, workInProgress, renderExpirationTime);
case HostText:
return updateHostText(current$$1, workInProgress);
...
}
}
复制代码
函数 beginWork 始终返回指向要在循环中处理的下一个子节点的指针或 null。
五、当匹配到ClassComponent
return updateClassComponent(current$$1, workInProgress, _Component2, _resolvedProps, renderExpirationTime);
复制代码
更新组件函数-updateClassComponent
function updateClassComponent(current$$1, workInProgress, Component, nextProps, renderExpirationTime) {
...
var nextUnitOfWork = finishClassComponent(current$$1, workInProgress, Component, shouldUpdate, hasContext, renderExpirationTime);
return nextUnitOfWork;
}
复制代码
六、结束组件函数-finishClassComponent
function finishClassComponent(current$$1, workInProgress, Component, shouldUpdate, hasContext, renderExpirationTime) {
...
var instance = workInProgress.stateNode;
...
var nextChildren = void 0;
...
// 这里会调用React组件里面的render函数获取返回值
nextChildren = instance.render();
...
// 协调算法的核心--查找child节点
reconcileChildren(current$$1, workInProgress, nextChildren, renderExpirationTime)
...
return workInProgress.child;
}
复制代码
七、协调算法核心之一-肯定child节点
function reconcileChildren(current$$1, workInProgress, nextChildren, renderExpirationTime) {
if (current$$1 === null) {
workInProgress.child = mountChildFibers(workInProgress, null, nextChildren, renderExpirationTime);
} else {
workInProgress.child = reconcileChildFibers(workInProgress, current$$1.child, nextChildren, renderExpirationTime);
}
}
复制代码
继续看下面函数的定义,了解workInProgress.child是被赋了什么值。
// mountChildFibers和reconcileChildFibers调用了同一个方法,分别是首次加载和后续更新时的执行逻辑
var reconcileChildFibers = ChildReconciler(true);
var mountChildFibers = ChildReconciler(false);
function ChildReconciler(shouldTrackSideEffects) {
function deleteChild(returnFiber, childToDelete) {
...
}
...
// 协调单个元素(协调核心方法也会调用这里哦)
function reconcileSingleElement(returnFiber, currentFirstChild, element, expirationTime) {
var key = element.key;
var child = currentFirstChild;
while (child !== null) {
...
child = child.sibling;
}
if (element.type === REACT_FRAGMENT_TYPE) {
// 这里经过函数名就能够知道,createFiberFromFragment将根据render函数返回值里面的Fragment元素建立Fiber对象。
var created = createFiberFromFragment(element.props.children, returnFiber.mode, expirationTime, element.key);
created.return = returnFiber;
// 天哪!终于有返回值了,是一个Fiber节点对象
return created;
} else {
// createFiberFromElement将根据render函数返回值里面的DOM元素建立Fiber对象
var _created4 = createFiberFromElement(element, returnFiber.mode, expirationTime);
_created4.ref = coerceRef(returnFiber, currentFirstChild, element);
_created4.return = returnFiber;
// 返回一个Fiber节点对象
return _created4;
}
}
...
// 这里才是核心方法
function reconcileChildFibers(returnFiber, currentFirstChild, newChild, expirationTime) {
...
// 处理对象类型
var isObject = typeof newChild === 'object' && newChild !== null;
if (isObject) {
switch (newChild.$$typeof) {
case REACT_ELEMENT_TYPE:
// 注意这里哦,会调用上面定义的函数
return placeSingleChild(reconcileSingleElement(returnFiber, currentFirstChild, newChild, expirationTime));
case REACT_PORTAL_TYPE:
return placeSingleChild(reconcileSinglePortal(returnFiber, currentFirstChild, newChild, expirationTime));
}
}
...
return reconcileChildFibers;
}
复制代码
完成每件有意义的事情都会须要咱们不懈的坚持。 若是你坚持看到了这里,请为本身点个赞。
在React协调算法执行过程当中,会遇到不少不少的case
,在这篇文章中咱们仅仅是对ClassComponent
类型的组件抓住一条主线进行深刻的剖析。其余类型好比HostRoot
、HostComponent
等能够按照上述分析思路进行探索。
文章开头提供的两篇文章对“协调算法”作了很好的理论分析,在理论分析的基础上,在React内部执行到renderRoot()
函数内部时,经过逐级剖析源码中相关函数的主体(省略了不少判断以及校验等逻辑),分析了root
对象上面的组件如何一步步被解析成对应的React元素树。