5

前言

上一篇介绍了react-dom,再往后面写很多都是在操作FiberRoot和Fiber这两个数据结构,这里简单的介绍一下,另外希望大家可以把他当成一个普通的数据结构来看,暂时不要把它跟react里面的各种逻辑结合到一起学习,看不懂的属性就过,就当它有这么个属性就可以了

fiber数据结构

fiber.png

  • 整个fiber是个单链表的属性结构
  • 根FiberRoot
  • 通过current指向一个FiberNode,这个current也称为RootFiber,是一个HostRoot类型fiber,也是所有fiber节点的根
  • 每个Fiber节点通过child指向下一个Fiber节点
  • Fiber节点中在通过return指向父节点
  • 通过sibling指向兄弟节点

其实就是几个指针指来指去,如果这里就看不懂,可以去看看我很早以前写的一些数据结构的文章哈

FiberNode

Fiber

一个Fiber的初始化代码

class FiberNode {
  constructor(tag, pendingProps, key, mode) {
    // 实例属性
    this.tag = tag; // 标记不同组件类型,如classComponent,functionComponent
    this.key = key; // react元素上的key 就是jsx上写的那个key,也就是最终ReactElement上的
    this.elementType = null; // createElement的第一个参数,ReactElement上的type
    this.type = null; // 表示fiber的真实类型 ,elementType基本一样,在使用了懒加载之类的功能时可能会不一样
    this.stateNode = null; // 实例对象,比如class组件new完后就挂载在这个属性上面,如果是RootFiber,那么它上面挂的是FiberRoot

    // fiber
    this.return = null; // 父节点,指向上一个fiber
    this.child = null; // 子节点,指向自身下面的第一个fiber
    this.sibling = null; // 兄弟组件, 指向一个兄弟节点
    
    this.index = 0; //  一般如果没有兄弟节点的话是0 当某个父节点下的子节点是数组类型的时候会给每个子节点一个index,index和key要一起做diff

    this.ref = null; // reactElement上的ref属性

    this.pendingProps = pendingProps; // 新的props
    this.memoizedProps = null; // 旧的props
    this.updateQueue = null; // fiber上的更新队列 执行一次setState就会往这个属性上挂一个新的更新, 每条更新最终会形成一个链表结构,最后做批量更新
    this.memoizedState = null; // 对应memoizedProps,上次渲染的state,相当于当前的state,理解成prev和next的关系

    this.mode = mode; // 表示当前组件下的子组件的渲染方式

    // effects

    this.effectTag = NoEffect; // 表示当前fiber要进行何种更新
    this.nextEffect = null; // 指向下个需要更新的fiber
  
    this.firstEffect = null; // 指向所有子节点里,需要更新的fiber里的第一个
    this.lastEffect = null; // 指向所有子节点中需要更新的fiber的最后一个

    this.expirationTime = NoWork; // 过期时间,代表任务在未来的哪个时间点应该被完成
    this.childExpirationTime = NoWork; // child过期时间

    this.alternate = null; // current树和workInprogress树之间的相互引用
  }
}
  • 以上就是整个fiber的初始化属性,其中跟结构有关系的就三个属性
  • return: 父节点,指向上一个fiber
  • child : 子节点,指向自身下面的第一个fiber
  • sibling : 兄弟组件, 指向一个兄弟节点
  • 它的遍历过程:

    1. 从current(Root)开始通过child向下找
    2. 如果有child先遍历子节点,直到null为止
    3. 然后看是否有兄弟节点
    4. 有兄弟节点则遍历兄弟节点
    5. 然后再看兄弟节点是否有子节点
    6. 然后return看父节点是否有兄弟节点
    7. 直到root

下面是我随意写的时候直接打的一段遍历伪代码,随便看看

function mountFiberRecursively(fiber){
    if(fiber.child !== null){
        mountFiberRecursively(fiber.child)
    }
    if(fiber.sibling !== null){
        mountFiberRecursively(fiber.sibling);
        return;
    }
}

accord
1.3k 声望187 粉丝

希望遇到一个公司,遇到一个团队,大家都愿意把code当作一种艺术去书写


下一篇 »
微前端