什么是fiber?
Fiber 可以理解为是一个执行单元,也可以理解为是一种数据结构。
执行单元的理解如下:
一种数据结构的理解如下: Fiber 还可以理解为是一种数据结构,React Fiber 就是采用链表实现的。每个 Virtual DOM 都可以表示为一个 fiber,如下图所示,每个节点都是一个 fiber。一个 fiber包括了 child(第一个子节点)、sibling(兄弟节点)、return(父节点)等属性,React Fiber 机制的实现,就是依赖于以下的数据结构。如下:
fiber结构是使用链表实现,在这里我们看看Fiber的链表结构是怎样的,如下图:
以上每一个单元包含了payload(数据)和nextUodate(指向下一个单元的指针),定义结构如下:
class Update {
constructor(payload, nextUpdate) {
this.payload = payload // payload 数据
this.nextUpdate = nextUpdate // 指向下一个节点的指针
}
}
接下来定义一个队列,把每个单元串联起来,其中定义了两个指针:头指针firstUpdate和尾指针lastUpdate,作用是指向第一个单元和最后一个单元,并加入了baseState属性存储React中的state状态。如下所示:
class UpdateQueue {
constructor() {
this.baseState = null // state
this.firstUpdate = null // 第一个更新
this.lastUpdate = null // 最后一个更新
}
}
接下来定义两个方法:插入节点单元(enqueueUpdate)、更新队列(forceUpdate)。插入节点单元时需要考虑是否已经存在节点,如果不存在直接将firstUpdate、lastUpdate指向此节点即可。更新队列是遍历这个链表,根据payload中的内容去更新state的值。
class UpdateQueue {
//.....
enqueueUpdate(update) {
// 当前链表是空链表
if (!this.firstUpdate) {
this.firstUpdate = this.lastUpdate = update
} else {
// 当前链表不为空
this.lastUpdate.nextUpdate = update
this.lastUpdate = update
}
}
// 获取state,然后遍历这个链表,进行更新
forceUpdate() {
let currentState = this.baseState || {}
let currentUpdate = this.firstUpdate
while (currentUpdate) {
// 判断是函数还是对象,是函数则需要执行,是对象则直接返回
let nextState = typeof currentUpdate.payload === 'function' ? currentUpdate.payload(currentState) : currentUpdate.payload
currentState = { ...currentState, ...nextState }
currentUpdate = currentUpdate.nextUpdate
}
// 更新完成后清空链表
this.firstUpdate = this.lastUpdate = null
this.baseState = currentState
return currentState
}
}
### Fiber节点设计
Fiber 的拆分单位是 fiber(fiber tree上的一个节点),实际上就是按虚拟DOM节点拆,我们需要根据虚拟dom去生成 Fiber 树。下文中我们把每一个节点叫做 fiber 。fiber 节点结构如下,源码详见
ReactInternalType
{
type: any, // 对于类组件,它指向构造函数;对于DOM元素,它指定HTML tag
key: null | string, // 唯一标识符
stateNode: any, // 保存对组件的类实例,DOM节点或与fiber节点关联的其他React元素类型的引用
child: Fiber | null, // 大儿子
sibling: Fiber | null, // 下一个兄弟
return: Fiber | null, // 父节点
tag: WorkTag, // 定义fiber操作的类型, 详见https://github.com/facebook/react/blob/master/packages/react-reconciler/src/ReactWorkTags.js
nextEffect: Fiber | null, // 指向下一个节点的指针
updateQueue: mixed, // 用于状态更新,回调函数,DOM更新的队列
memoizedState: any, // 用于创建输出的fiber状态
pendingProps: any, // 已从React元素中的新数据更新,并且需要应用于子组件或DOM元素的props
memoizedProps: any, // 在前一次渲染期间用于创建输出的props
// ……
}