React Fiber是React 16版本引入的一种全新的协调引擎,用于优化和改善React应用的性能和可扩展性。React Fiber旨在解决React在处理复杂应用时的一些局限性,使其能够更高效地管理和更新UI。
React Fiber的作用
- 协调的可中断性:js遇到任务不可中断执行,有了
fiber后可以中断,可恢复执行上下文的任务,通过将渲染过程分解成可中断的工作单元,React Fiber可以更好地响应用户输入,减少卡顿现象,提高用户体验。(同步不可中断--->异步可中断) - 任务的优先级:React Fiber引入了优先级和调度机制,以
确保高优先级任务能够及时执行。React会根据任务的优先级动态调整执行顺序。(scheduler 任务的优先级) - 错误边界:提高错误处理能力,在渲染过程中能够更好地捕获和处理错误。
Fiber节点
Fiber节点是一个Javascript对象,表示一个React对象。每个Fiber节点的属性:
- 类型:React元素的类型(
tag) - 键值:唯一标识元素的键值(用于列表渲染)(
key) - 状态:组件的局部状态(
flags) - DOM的引用:与Fiber节点关联的DOM元素(
stateNode)
function FiberNode(){
this.tag = tag; //元素类型
this.key = key;//元素的唯一标识。
this.elementType = null; //元素类型
this.type = null;//元素类型
this.stateNode = null;//元素实例的状态节点
// Fiber
this.return = null;//该组件实例的父级。
this.child = null;//该组件实例的第一个子级。
this.sibling = null;//该组件实例的下一个兄弟级
this.index = 0;//该组件实例在父级的子级列表中的位置。
this.ref = null;//该组件实例的ref属性
this.refCleanup = null;//ref的清理函数
this.pendingProps = pendingProps;//待处理的props(最新的)
this.memoizedProps = null;//处理后的props(上一次)
this.updateQueue = null;//TODO
this.memoizedState = null;//类组件保存state信息,函数组件保存hooks信息
this.dependencies = null;//该组件实例的依赖列表
this.mode = mode;//该组件实例的模式 (DOM模式和Canvas模式)
// Effectsx
this.flags = NoFlags$1;//副作用标签 ,之前的版本是effectTag
this.subtreeFlags= NoFlags$1;//子节点副作用标签。
this.deletions = null;//待删除的子树列表。
this.lanes = NoLanes;//任务更新的优先级区分
this.childLanes = NoLanes;//子树任务更新的优先级区分
this.alternate = null;//组件实例的备份实例,用于记录前一次更新的状态。更新时候 workInProgress会复用当前值
}
先写成一个DOM,再转为对象,再转为一个真实的DOM元素
手写createElement
function createElement(type, props, ...children) {
return {
type,
props: {
...props,
children,
},
};
}
手写render
render的过程就是转换为一个真实DOM元素的过程
ReactDOM.render(<App />, document.getElementById("root"))
function render(vDom,container){
let dom;
// 检查当前节点是文本还是对象
if(typeof vDom !== "object"){
dom = document.createTextNode(vDom);
}else{
dom = document.createElement(vDom.type);
}
if(vDom.props){
Object.keys(vDom.props)
.filter(key => key != "children")
.forEach(item=>{
dom[item] = vDom.props[item];
})
}
if(vDom.props && vDom.props.children && vDom.props.children.length){
vDom.props.children.forEach(item=>{
render(item,dom);
})
}
}