hushicai / hushicai.github.io

Blog
https://hushicai.github.io
27 stars 1 forks source link

React Fiber核心数据结构 #40

Open hushicai opened 5 years ago

hushicai commented 5 years ago

示例

ReactDOM.render(
  <h1>Hello World!</h1>,
  document.getElementById('container')
);

以上代码来自fixtures/packaging/babel-standalone/dev.html

hushicai commented 5 years ago

ReactRoot

当调用ReactDOM.render方法时,首先会创建一个ReactRoot实例,然后调用ReactRoot.render方法,进入渲染流程:

key type
render Function
unmount Function
_internalRoot FiberRootNode

当前放在ReactDOM.js中,可以理解为React渲染的入口。

hushicai commented 5 years ago

FiberRootNode

每个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

image

hushicai commented 5 years ago

FiberNode

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结构请看这里

hushicai commented 5 years ago

Update

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
hushicai commented 5 years ago

UpdateQueue

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
hushicai commented 4 years ago

Effects List

React通过FiberNode中的firstEffect、nextEffect、lastEffect字段构建了一个链表:

image

这是是一个深度优先遍历的过程,展开来看:

image

图片来自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;
  }