什么是fiber?
一个fiber本质上是一个Fiber类的实例,以下是实例中的各个属性。可以看出,每一个Fiber节点之间通过指针相互关联,并找到下一个Fiber节点。因此,所有的Fiber节点相互关联就形成了Fiber树。
kotlin
// 静态 Instance
this.tag = tag //组件类型
this.key = key
this.elementType = null //和type大部分时间相同,除非使用react.memo包裹函数
this.type = null //和elementType大部分时间相同
this.stateNode = null // 对应真实dom节点
// Fiber //链表关系
this.return=null // 关联父节点
this.child=null // 关联子节点
this.sibling=null // 关联兄弟节点
this.index=0 // 同级fiber节点,代表它们插入dom的索引
this.ref = null // 字面意思,就是ref
/*------------------------作为动态单元的属性---------------------------*/
this.pendingProps = pendingProps
this.memoizedProps = null
this.updateQueue = null
this.memoizeState = null
this.dependencies = null
this.mode = mode
// Effects // 名称中带有effect的和副作用相关,
this.effectTag = NoEffect
this.subtreeTag = NoSubtreeEffect
this.deletions = null
this.nextEffect = null
this.firstEffect = null
this.lastEffect = null
this.lanes = NoLanes // 和优先级调度有关
this.childLanes = NoLanes
this.alternate = null // 与fiber架构的双缓存机制有关
Fiber节点是如何产生的呢?
Fiber树的产生源自于JSX模板,如以下代码:
假设我们有一个简单的 React 函数组件 ExampleComponent
:
javascript
function ExampleComponent() {
return (
<div className="container">
<h1>Hello, World!</h1>
<p>This is an example component.</p>
</div>
);
}
首先,webpack编译时,Babel将其转化为普通的JS代码,在这里,React.createElement的三个参数:元素类型、属性对象和子元素。
jsx
function ExampleComponent() {
return React.createElement(
'div',
{ className: 'container' },
React.createElement('h1', null, 'Hello, World!'),
React.createElement('p', null, 'This is an example component.')
);
}
React.createElement做了什么事情呢?
React.createElement()
是 React 中用于创建虚拟 DOM 元素的函数。它接收三个参数:类型、属性对象和子元素,然后返回一个描述该元素的 JavaScript 对象
javascript
function createElement(type, props, ...children) {
return {
type,
props: {
...props,
children: children.map(child =>
typeof child === "object" ? child : createTextElement(child)
)
}
};
}
function createTextElement(text) {
return {
type: "TEXT_ELEMENT",
props: {
nodeValue: text,
children: []
}
};
}
上述代码是一个简化版的示例,实际的 React.createElement()
实现还包含其他功能,例如处理 key
和 ref
等特殊属性,以及一些性能优化。以下是编译后的产物,可以认为是vNode
json
{
"type": "div",
"props": {
"className": "container",
"children": [{
"type": "h1",
"props": {
"children": [{
"type": "TEXT_ELEMENT",
"props": {
"nodeValue": "Hello, World!",
"children": []
}
}]
}
}, {
"type": "p",
"props": {
"children": [{
"type": "TEXT_ELEMENT",
"props": {
"nodeValue": "This is an example component.",
"children": []
}
}]
}
}]
}
}
vNode 转化为 Fiber 结构:
javascript
// 定义 Fiber 对象
class Fiber {
constructor(vNode) {
this.type = vNode.type;
this.props = vNode.props;
this.key = vNode.key;
this.child = null;
this.sibling = null;
this.alternate = null;
// 其他需要用到的属性和状态
}
}
// 构建 Fiber 树
function createFiberTree(vNode) {
const fiber = new Fiber(vNode);
if (vNode.children) {
let prevChildFiber = null;
vNode.children.forEach(childVNode => {
const childFiber = createFiberTree(childVNode);
if (prevChildFiber === null) {
fiber.child = childFiber;
} else {
prevChildFiber.sibling = childFiber;
}
prevChildFiber = childFiber;
});
}
return fiber;
}
// 将 vNode 转化为 Fiber 结构
const fiberTree = createFiberTree(vNode);
createFiberTree
函数用于递归构建 Fiber 树,根据 vNode 的层次结构创建相应的 Fiber 对象,并将子节点和兄弟节点连接起来。 生成的Fiber节点如下
javascript
const exampleFiber = {
type: "div",
props: {
className: "container",
},
child: Fiber {
type: 'h1',
props: { children: "Hello, World!" },
key: null,
child: null,
sibling: Fiber { ... },
alternate: null,
},
sibling: null,
return: null
};
exampleFiber.child = {
type: "h1",
props: { children: "Hello, World!" },
child: null,
sibling: null,
return: exampleFiber
};
exampleFiber.child.sibling = {
type: "p",
props: { children: "This is an example component." },
child: null,
sibling: null,
return: exampleFiber
};
在上述代码中,我们创建了两个子节点的 Fiber 对象,并将它们连接到父节点 exampleFiber
的 child
和 sibling
属性上。通过这种方式,我们可以构建出一个简单的 Fiber 树结构。
在这里能得到的一个信息是,每一个元素都会变成一个Fiber节点。当后续这些元素关联的变量发生改变时,它又是怎样去触发更新的呢?