原理篇:fiber
一、Fiber基础
什么是fiber
fiber是react中最小的执行单位,可以理解为fiber就是虚拟DOM。
更新 fiber 的过程叫做 Reconciler(调和器)
element,fiber, DOM 之间的关系?
- element 就是jsx语法,通过React.createElement创建成element对象.
- DOM 就是浏览器的DOM
- fiber:每一次的 element 变化都会通过 调和 fiber 来 触发真实 DOM 渲染。
fiber保存了哪些信息
function FiberNode(){
....
this.key = key; // key调和子节点时候用到。
this.return = null; // 指向父级fiber
this.child = null; // 指向子级fiber
this.sibling = null; // 指向兄弟fiber
this.index = 0; // 索引
this.expirationTime = NoWork; // 通过不同过期时间,判断任务是否过期, 在v17版本用lane表示。
this.alternate = null; //双缓存树,指向缓存的fiber。更新阶段,两颗树互相交替。
....
}
每一个 element 都会对应一个 fiber ,每一个 fiber 是通过 return , child ,sibling 三个属性建立起联系的。
- return: 指向父级 Fiber 节点。
- child:指向子 Fiber 节点。
- sibling:指向兄弟 fiber 节点。
元素结构如下代码:
export default class Index extends React.Component{
state={ number:666 }
handleClick=()=>{
this.setState({
number:this.state.number + 1
})
}
render(){
return <div>
hello,world
<p > 《React进阶实践指南》 { this.state.number } 👍 </p>
<button onClick={ this.handleClick } >点赞</button>
</div>
}
}
fiber对应的关系如下:
二、Fiber更新机制
初始化
第一步:创建fiberRoot和rootFiber
- fiberRoot: 首次构建应用, 创建一个 fiberRoot ,作为整个 React 应用的根基。
ReactDOM.render(<Index/>, document.getElementById('app'));
- rootFiber: 通过 ReactDOM.render 渲染出来的。比如一个组件会渲染一个rootFiber。
rootFiber可以有多个,但fiberRoot只能有一个。
第二步:创建workInProgress树
- workInProgress:内存中构建的 Fiber 树。
- current:正在视图层渲染的树叫做 current 树。
渲染流程中,先复用current树(rootFiber)的alternate 作为 workInProgress。
第三步:深度调和子节点,渲染视图
遍历fiber树,以workInProgress 作为最新的渲染树,即current Fiber 树。
更新
重复上述第二和第三步。
总结:workInProgress是内存中构建的树,current是当前正在渲染的树,这两棵树通过alternate 指针相互关联,在下一次渲染的时候直接使用缓存树作为下次的渲染树
三 两大阶段:render和commit
render
render阶段主要涉及两个过程: beginWork 和 completeUnitOfWork。
beginWork
- 执行部分生命周期和render,得到最新的 children
- 向下遍历调和 children ,复用 oldFiber
- 打不同的副作用标签effectTag,比如类组件的生命周期,或者元素的增加,删除,更新。
completeUnitOfWork
completeUnitOfWork 的流程是自下向上的
- 将effectTag 的 Fiber 节点保存到 effectList 的单向链表中。 在 commit 阶段,将不再需要遍历每一个 fiber ,只需要执行更新 effectList 就可以了。
- 处理组件的context,初始化元素标签,生成真实DOM,处理props,等
commit
commit 可以分为3个阶段:
- Before mutation 阶段(执行 DOM 操作前);
- mutation 阶段(执行 DOM 操作);
- layout 阶段(执行 DOM 操作后)
- Before mutation
- 对于类组件,执行 getSnapshotBeforeUpdate 生命周期
- 对于函数组件,异步调用 useEffect
- Mutation
- 进行真实的 DOM 操作
- Layout
- 对于类组件,会执行setState的callback
- 对于函数组件,会执行useLayoutEffect
备注:
本文学习总结自: 《React 进阶实践指南》