React Fiber

130 阅读2分钟

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);
    })
  }
}