# 创建Fiber树
# demo
import React, { useState } from "react";
export default function App() {
const [count, setCount] = useState(0);
return (
<>
<h1
onClick={() => {
setCount(() => count + 1);
}}
>
<p title={count}>{count}</p>
</h1>
</>
);
}
react渲染的时候分为两个阶段,第一阶段称为render、第二阶段称为commit。render阶段主要工作是构建Fiber树和生成effectList。因为render阶段涉及代码有些多,所以先整理构建Fiber树相关的代码。比如以上的demo是如何创建Fiber树的
# 创建Fiber树过程(mount阶段)
在上面创建根节点末尾会看到已经形成了Fiber树的开始阶段,此时workInPoress(即Fiber双缓存中正在构建或更新的那颗树)还是不存在的。此时会创建workInProgess所对应的方法是createWorkInPoegress。
具体的是如何进入到这个方法的可以调试看代码执行栈。
function createWorkInProgress(current, pendingProps) {
var workInProgress = current.alternate;
if (workInProgress === null) {
workInProgress = createFiber(current.tag, pendingProps, current.key, current.mode);
workInProgress.elementType = current.elementType;
workInProgress.type = current.type;
workInProgress.stateNode = current.stateNode;
workInProgress.alternate = current;
current.alternate = workInProgress;
} else {
// ...
}
workInProgress.childLanes = current.childLanes;
workInProgress.lanes = current.lanes;
workInProgress.child = current.child;
workInProgress.memoizedProps = current.memoizedProps;
workInProgress.memoizedState = current.memoizedState;
workInProgress.updateQueue = current.updateQueue; // Clone the dependencies object. This is mutated
var currentDependencies = current.dependencies;
workInProgress.dependencies = currentDependencies === null ? null : {
lanes: currentDependencies.lanes,
firstContext: currentDependencies.firstContext
}; // These will be overridden during the parent's reconciliation
workInProgress.sibling = current.sibling;
workInProgress.index = current.index;
workInProgress.ref = current.ref;
{
workInProgress.selfBaseDuration = current.selfBaseDuration;
workInProgress.treeBaseDuration = current.treeBaseDuration;
}
{
workInProgress._debugNeedsRemount = current._debugNeedsRemount;
switch (workInProgress.tag) {
case IndeterminateComponent:
case FunctionComponent:
case SimpleMemoComponent:
workInProgress.type = resolveFunctionForHotReloading(current.type);
break;
case ClassComponent:
workInProgress.type = resolveClassForHotReloading(current.type);
break;
case ForwardRef:
workInProgress.type = resolveForwardRefForHotReloading(current.type);
break;
}
}
return workInProgress;
} // Used to reuse a Fiber for a second pass.
在mount阶段调用workInPoress就是一大堆很单纯的赋值操作,注意在createWorkInProgress的时候有这样两句代码
workInProgress.alternate = current;
current.alternate = workInProgress;
这两句代码就是将current树和workInProgress相连。此时的Fiber树为
接着会循环调用performUnitOfwork来为workInProgress添加子节点。performUnitOfwork算是一个比较重要的函数了,日后再说。performUnitOfWork中又调用一系列方法调用reconcileChildren。就是这个方法为workInProgress创建子节点
function reconcileChildren(current, workInProgress, nextChildren, renderLanes) {
if (current === null) {
workInProgress.child = mountChildFibers(workInProgress, null, nextChildren, renderLanes);
} else {
workInProgress.child = reconcileChildFibers(workInProgress, current.child, nextChildren, renderLanes);
}
}
这里当初看的时候确实很懵,但是mountChildFibers和reconcileChildFibers真的是同一个方法
var reconcileChildFibers = ChildReconciler(true);
var mountChildFibers = ChildReconciler(false);
大概就是这样。只是传参不同。具体在render阶段再说.而且最终会调用另一个reconcileChildFibers方法。这两个方法没有联系只是命名不同
function reconcileChildFibers(returnFiber, currentFirstChild, newChild, lanes) {
var isUnkeyedTopLevelFragment = typeof newChild === 'object' && newChild !== null && newChild.type === REACT_FRAGMENT_TYPE && newChild.key === null;
if (isUnkeyedTopLevelFragment) {
newChild = newChild.props.children;
} // Handle object types
var isObject = typeof newChild === 'object' && newChild !== null;
if (isObject) {
switch (newChild.$$typeof) {
case REACT_ELEMENT_TYPE:
return placeSingleChild(reconcileSingleElement(returnFiber, currentFirstChild, newChild, lanes));
case REACT_PORTAL_TYPE:
return placeSingleChild(reconcileSinglePortal(returnFiber, currentFirstChild, newChild, lanes));
case REACT_LAZY_TYPE:
{
var payload = newChild._payload;
var init = newChild._init; // TODO: This function is supposed to be non-recursive.
return reconcileChildFibers(returnFiber, currentFirstChild, init(payload), lanes);
}
}
}
if (typeof newChild === 'string' || typeof newChild === 'number') {
return placeSingleChild(reconcileSingleTextNode(returnFiber, currentFirstChild, '' + newChild, lanes));
}
if (isArray$1(newChild)) {
return reconcileChildrenArray(returnFiber, currentFirstChild, newChild, lanes);
}
if (getIteratorFn(newChild)) {
return reconcileChildrenIterator(returnFiber, currentFirstChild, newChild, lanes);
}
if (isObject) {
throwOnInvalidObjectType(returnFiber, newChild);
}
{
if (typeof newChild === 'function') {
warnOnFunctionType(returnFiber);
}
}
//...
return deleteRemainingChildren(returnFiber, currentFirstChild);
}
return reconcileChildFibers;
}
这里会根据newChild也就是jsx的children类型来判断走哪个。具体都差不多比如reconcileSingleElement
function reconcileSingleElement(returnFiber, currentFirstChild, element, lanes) {
var key = element.key;
var child = currentFirstChild;
while (child !== null) {
// 此时child肯定为null的
}
if (element.type === REACT_FRAGMENT_TYPE) {
var created = createFiberFromFragment(element.props.children, returnFiber.mode, lanes, element.key);
created.return = returnFiber;
return created;
} else {
var _created4 = createFiberFromElement(element, returnFiber.mode, lanes);
_created4.ref = coerceRef(returnFiber, currentFirstChild, element);
_created4.return = returnFiber;
return _created4;
}
}
调用createFiberFromElement创建Fiber。同时用return指向了父节点
function createFiberFromElement(element, mode, lanes) {
var owner = null;
{
owner = element._owner;
}
var type = element.type;
var key = element.key;
var pendingProps = element.props;
var fiber = createFiberFromTypeAndProps(type, key, pendingProps, owner, mode, lanes);
{
fiber._debugSource = element._source;
fiber._debugOwner = element._owner;
}
return fiber;
}
分离出type、key等值后调用createFiberFromTypeAndProps方法创建Fiber。这个方法顾名思义。其实内部也是调用createFiber方法具体日后再说。
在循环所有的子节点并创建Fiber。用child和return将所有Fiber节点相连后就能得到workInProgress。然后在commit阶段会有一句
root.current = finishedWork;
将FiberRootNode的curreng指向WorkInProgress。至此Fiber树结构为
# 创建Fiber树过程(update阶段)
update阶段和mount阶段所调用的函数差不多。区别在于进入createWorkInProgress方法时。此时worrkInProgress不为null。会进入到else的逻辑
function createWorkInProgress(current, pendingProps) {
var workInProgress = current.alternate;
if{
//...
} else {
workInProgress.pendingProps = pendingProps; // Needed because Blocks store data on type.
workInProgress.type = current.type; // We already have an alternate.
workInProgress.flags = NoFlags; // The effect list is no longer valid.
workInProgress.nextEffect = null;
workInProgress.firstEffect = null;
workInProgress.lastEffect = null;
{
workInProgress.actualDuration = 0;
workInProgress.actualStartTime = -1;
}
}
//...
workInProgress.child = current.child;
//...
return workInProgress;
} // Used to reuse a Fiber for a second pass.
接着在进入reconcileSingleElement时child也不为null会进入到while的逻辑
function reconcileSingleElement(returnFiber, currentFirstChild, element, lanes) {
var key = element.key;
var child = currentFirstChild;
while (child !== null) {
if (child.key === key) {
switch (child.tag) {
case Fragment:
{
if (element.type === REACT_FRAGMENT_TYPE) {
deleteRemainingChildren(returnFiber, child.sibling);
var existing = useFiber(child, element.props.children);
existing.return = returnFiber;
{
existing._debugSource = element._source;
existing._debugOwner = element._owner;
}
return existing;
}
break;
}
case Block:
{
var type = element.type;
if (type.$$typeof === REACT_LAZY_TYPE) {
type = resolveLazyType(type);
}
if (type.$$typeof === REACT_BLOCK_TYPE) {
if (type._render === child.type._render) {
deleteRemainingChildren(returnFiber, child.sibling);
var _existing2 = useFiber(child, element.props);
_existing2.type = type;
_existing2.return = returnFiber;
{
_existing2._debugSource = element._source;
_existing2._debugOwner = element._owner;
}
return _existing2;
}
}
}
default:
{
if (child.elementType === element.type || ( // Keep this check inline so it only runs on the false path:
isCompatibleFamilyForHotReloading(child, element) )) {
deleteRemainingChildren(returnFiber, child.sibling);
var _existing3 = useFiber(child, element.props);
_existing3.ref = coerceRef(returnFiber, child, element);
_existing3.return = returnFiber;
{
_existing3._debugSource = element._source;
_existing3._debugOwner = element._owner;
}
return _existing3;
}
break;
}
} // Didn't match.
deleteRemainingChildren(returnFiber, child);
break;
} else {
deleteChild(returnFiber, child);
}
child = child.sibling;
}
//...
}
与mount阶段不同的是此时会调用useFiber克隆一个Fiber节点(只针对此demo具体更新和diff算法相关)。最后也会用这两句代码将workInProgress和current交换
root.current = finishedWork;
最终形成的Fiber树如下