08.React源码学习-FiberRoot与Fiber

React中的数据结构

FiberRoot

什么是 FiberRoot?

  • 整个应用的起点
  • 包含应用挂载的目标节点
  • 记录整个应用更新过程的各种信息

结构如下:

type BaseFiberRootProperties = {|
    // root节点,render方法接收的第二个参数
  containerInfo: any,
    // 只有在持久更新中会用到,也就是不支持增量更新的平台,react-dom不会用到
  pendingChildren: any,
    // 当前应用对应的Fiber对象,是Root Fiber
  current: Fiber,
    // 一下的优先级是用来区分
    // 1) 没有提交(committed)的任务
    // 2) 没有提交的挂起任务
    // 3) 没有提交的可能被挂起的任务
    // 我们选择不追踪每个单独的阻塞登记,为了兼顾性能
    // The earliest and latest priority levels that are suspended from committing.
    // 最老和新的在提交的时候被挂起的任务
  earliestSuspendedTime: ExpirationTime,
  latestSuspendedTime: ExpirationTime,
    // The earliest and latest priority levels that are not known to be suspended.
    // 最老和最新的不确定是否会挂起的优先级(所有任务进来一开始都是这个状态)
  earliestPendingTime: ExpirationTime,
  latestPendingTime: ExpirationTime,
    // The latest priority level that was pinged by a resolved promise and can
    // be retried.
    // 最新的通过一个promise被reslove并且可以重新尝试的优先级
  latestPingedTime: ExpirationTime,
    // 如果有错误被抛出并且没有更多的更新存在,我们尝试在处理错误前同步重新从头渲染
    // 在`renderRoot`出现无法处理的错误时会被设置为`true`
  didError: boolean,
    // 正在等待提交的任务的`expirationTime`
  pendingCommitExpirationTime: ExpirationTime,
    // 已经完成的任务的FiberRoot对象,如果你只有一个Root,那他永远只可能是这个Root对应的Fiber,或者是null
    // 在commit阶段只会处理这个值对应的任务
  finishedWork: Fiber | null,
    // 在任务被挂起的时候通过setTimeout设置的返回内容,用来下一次如果有新的任务挂起时清理还没触发的timeout
  timeoutHandle: TimeoutHandle | NoTimeout,
    // 顶层context对象,只有主动调用`renderSubtreeIntoContainer`时才会有用
  context: Object | null,
  pendingContext: Object | null,
    // 用来确定第一次渲染的时候是否需要融合
  +hydrate: boolean,
    // 当前root上剩余的过期时间
    // TODO: 提到renderer里面区处理
  nextExpirationTimeToWorkOn: ExpirationTime,
    // 当前更新对应的过期时间
  expirationTime: ExpirationTime,
    // List of top-level batches. This list indicates whether a commit should be
    // deferred. Also contains completion callbacks.
    // TODO: Lift this into the renderer
    // 顶层批次(批处理任务?)这个变量指明一个commit是否应该被推迟
    // 同时包括完成之后的回调
    // 貌似用在测试的时候?
  firstBatch: Batch | null,
    // root之间关联的链表结构
  nextScheduledRoot: FiberRoot | null,
|};

Fiber

什么是Fiber?

  • 每一个ReactElement对应一个Fiber对象
  • 记录节点的各种状态
  • 串联整个应用形成树结构

结构如下:

// Fiber对应一个组件需要被处理或者已经处理了,一个组件可以有一个或者多个Fiber
type Fiber = {|
    // 标记不同的组件类型
  tag: WorkTag,
    // ReactElement里面的key
  key: null | string,
    // ReactElement.type,也就是我们调用`createElement`的第一个参数
  elementType: any,
    // The resolved function/class/ associated with this fiber.
    // 异步组件resolved之后返回的内容,一般是`function`或者`class`
  type: any,
    // The local state associated with this fiber.
    // 跟当前Fiber相关本地状态(比如浏览器环境就是DOM节点)
  stateNode: any,
    // 指向他在Fiber节点树中的`parent`,用来在处理完这个节点之后向上返回
  return: Fiber | null,
    // 单链表树结构
    // 指向自己的第一个子节点
  child: Fiber | null,
    // 指向自己的兄弟结构
    // 兄弟节点的return指向同一个父节点
  sibling: Fiber | null,
  index: number,
    // ref属性
  ref: null | (((handle: mixed) => void) & {_stringRef: ?string}) | RefObject,
    // 新的变动带来的新的props
  pendingProps: any, 
    // 上一次渲染完成之后的props
  memoizedProps: any,
    // 该Fiber对应的组件产生的Update会存放在这个队列里面
  updateQueue: UpdateQueue<any> | null,
    // 上一次渲染的时候的state
  memoizedState: any,
    // 一个列表,存放这个Fiber依赖的context
  firstContextDependency: ContextDependency<mixed> | null,
    // 用来描述当前Fiber和他子树的`Bitfield`
    // 共存的模式表示这个子树是否默认是异步渲染的
    // Fiber被创建的时候他会继承父Fiber
    // 其他的标识也可以在创建的时候被设置
    // 但是在创建之后不应该再被修改,特别是他的子Fiber创建之前
  mode: TypeOfMode,
    // Effect
    // 用来记录Side Effect
  effectTag: SideEffectTag,
    // 单链表用来快速查找下一个side effect
  nextEffect: Fiber | null,
    // 子树中第一个side effect
  firstEffect: Fiber | null,
    // 子树中最后一个side effect
  lastEffect: Fiber | null,
    // 代表任务在未来的哪个时间点应该被完成
    // 不包括他的子树产生的任务
  expirationTime: ExpirationTime,
    // 快速确定子树中是否有不在等待的变化
  childExpirationTime: ExpirationTime,
    // 在Fiber树更新的过程中,每个Fiber都会有一个跟其对应的Fiber
    // 我们称他为`current <==> workInProgress`
    // 在渲染完成之后他们会交换位置
  alternate: Fiber | null,
    // 下面是调试相关的,收集每个Fiber和子树渲染时间的
  actualDuration?: number,
    // If the Fiber is currently active in the "render" phase,
    // This marks the time at which the work began.
    // This field is only set when the enableProfilerTimer flag is enabled.
  actualStartTime?: number,
    // Duration of the most recent render time for this Fiber.
    // This value is not updated when we bailout for memoization purposes.
    // This field is only set when the enableProfilerTimer flag is enabled.
  selfBaseDuration?: number,
    // Sum of base times for all descedents of this Fiber.
    // This value bubbles up during the "complete" phase.
    // This field is only set when the enableProfilerTimer flag is enabled.
  treeBaseDuration?: number,
    // Conceptual aliases
    // workInProgress : Fiber ->  alternate The alternate used for reuse happens
    // to be the same as work in progress.
    // __DEV__ only
  _debugID?: number,
  _debugSource?: Source | null,
  _debugOwner?: Fiber | null,
  _debugIsCurrentlyTiming?: boolean,
|};
来看看Fiber是如何串联节点的:

有如下节点结构:

[图片上传失败...(image-7a8767-1595402718164)]

被Fiber处理成能高效遍历的树形结构后:

[图片上传失败...(image-88437b-1595402718164)]

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,188评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,464评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,562评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,893评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,917评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,708评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,430评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,342评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,801评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,976评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,115评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,804评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,458评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,008评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,135评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,365评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,055评论 2 355

推荐阅读更多精彩内容