Open hushicai opened 5 years ago
当调用ReactDOM.render
方法时,首先会创建一个ReactRoot
实例,然后调用ReactRoot.render
方法,进入渲染流程:
key | type |
---|---|
render | Function |
unmount | Function |
_internalRoot | FiberRootNode |
当前放在ReactDOM.js中,可以理解为React渲染的入口。
每个React应用程序都有一个或多个充当容器的DOM元素,例如在我们上面的例子中,ID为container的div元素就是一个DOM容器。
React会为每一个DOM容器创建一个FiberRootNode,其核心成员如下:
key | type |
---|---|
current | (HostRoot)FiberNode |
containerInfo | DOMContainer |
finishedWork | (HostRoot)FiberNode | null |
其中current
属性是一个类型为HostRoot的特殊FiberNode,它是Fiber Tree的根节点,充当最顶层组件(例如上述的h1)的父级。
我们可以通过DOM元素的引用来访问它:
const fiberRoot = document.querySelector('#container')._reactRootContainer._internalRoot
Fiber Reconciler核心数据结构是由FiberNode组成的节点树,其核心成员如下:
key | type | desc |
---|---|---|
tag | WorkTag | FiberNode的类型 |
stateNode | any | FiberNode会通过stateNode绑定其他对象,例如DOM、FiberRootNode、React组件实例等 |
return | FiberNode|null | 父节点 |
child | FiberNode|null | 第一个子节点 |
sibling | FiberNode|null | 第一个兄弟节点 |
alternate | FiberNode|null | 替身 |
pendingProps | Object | |
memoizedProps | Object | |
memoizedState | Object | |
updateQueue | UpdateQueue | 更新队列 |
effectTag | SideEffectTag | 二进制数字,用个标识某个动作,如Placement、Update、Deletion、Callback等 |
firstEffect | FiberNode|null | |
nextEffect | FiberNode|null | |
lastEffect | FiberNode|null |
完整的Fiber结构请看这里。
React使用Update来表示一次更新或渲染,其数据结构如下:
key | type | desc |
---|---|---|
tag | 0|1|2|3 | UpdateState = 0、ReplaceState = 1、ForceUpdate = 2、CaptureUpdate = 3 |
payload | any | |
callback | Function|null | 更新后的回调函数 |
next | Update|null | 下一个Update对象 |
nextEffect | Update|null |
UpdateQueue
表示在FiberNode中的更新队列,其核心数据结构如下:
key | type | desc |
---|---|---|
baseState | Object | |
firstUpdate | Update|null | 第一个Update |
lastUpdate | Update|null | 最后一个Update |
firstCapturedUpdate | Update|null | |
lastCapturedUpdate | Update|null | |
firstEffect | Update|null | |
lastEffect | Update|null |
React通过FiberNode中的firstEffect、nextEffect、lastEffect字段构建了一个链表:
这是是一个深度优先遍历的过程,展开来看:
图片来自https://indepth.dev/inside-fiber-in-depth-overview-of-the-new-reconciliation-algorithm-in-react/
一个Fiber的Effect List只包含它的子节点,没有它自己。
if (finishedWork.effectTag > PerformedWork) {
// A fiber's effect list consists only of its children, not itself. So if
// the root has an effect, we need to add it to the end of the list. The
// resulting list is the set that would belong to the root's parent, if it
// had one; that is, all the effects in the tree including the root.
if (finishedWork.lastEffect !== null) {
finishedWork.lastEffect.nextEffect = finishedWork;
firstEffect = finishedWork.firstEffect;
} else {
firstEffect = finishedWork;
}
} else {
// There is no effect on the root.
firstEffect = finishedWork.firstEffect;
}
示例
以上代码来自fixtures/packaging/babel-standalone/dev.html。