React 源码解析 - renderRoot 完成节点更新任务

completeUnitOfWork

当 beginWork 遍历到 fiber 树的单侧最下方时 next 为 null,这时候就会调用 completeUnitOfWork 完成节点并按遍历顺序设置新的 next 进行操作

performUnitOfWork 遍历 fiber 树的顺序

核心功能

  • 根据是否中断调用不同的处理方法
  • 当一侧的子节点被 beginWork 更新组件完了执行
  • beginWork 完成各个组件的 update,然后返回他的 child
  • 判断是否有兄弟节点来执行不同的操作
  • 完成节点之后复 effect 链

completeUnitOfWork 没有报错的处理流程

  • 当 workInProgress.effectTag 标记的不是 Incomplete,没有错误捕获
if ((workInProgress.effectTag & Incomplete) === NoEffect) { //.. }
  • completetWork 完成节点更新
  • resetChildExpirationTime 重置 childExpirationTime
  • 构建 effect 链
  • 按照遍历 fiber 树的顺序确定下 next 节点

resetChildExpirationTime 重置 workInProgress.childExpirationTime

  • 在 completeWork 完成节点更新后执行
  • 重置的是 workInProgress 上的 childExpirationTime 属性
  • 在当前节点上找到子节点把所有子节点中不是 NoWork 的最早过期时间赋值给当前节点的 childExpirationTime
  • childExpirationTime 来表示当前节点所有子节点中最高的更新的优先级

completeWork 完成节点更新

核心功能

  • pop 出各种 context 相关功能
  • 对 HostComponent 进行初始化
  • 初始化监听事件
  • 对大部分 tag 不进行操作或者只是 pop context
  • 只有 HostComponent, HostText, SuspenseComponent 有操作

HostComponent tag 的更新

tag 为 HostComponent 表示普通 dom 节点,如: div

核心功能

  • diffProperties 计算需要更新的内容
  • vdom 进行对比是否真的要更新
  • 不同 dom property 处理方式不同
  • 根据 current 原 fiber 节点和 workInProgress.stateNode 当前 dom 判断首次渲染还是更新渲染

初始更新

  • createInstance 根据当前更新的节点创建新的 dom 对象并记录创建的 fiber 和 props 属性
  • appendAllChildren 构建 dom 树,遍历顺序是从底向上只构建第一层的 child, child.sibling
  • finalizeInitialChildren 初始化属性,初始化事件监听
  • markUpdate 标记 effect = UPDATE,在 workInProgress.stateNode 上记录 instance

createInstance 创建 dom

  • 创建 dom 节点
  • 在 dom 节点对象上记录此次创建的 fiber 和 props 信息
  • createElement 创建 dom 对象

appendAllChildren 构建 dom 树

构建 dom 树, 都是 append 第一层 child 和 child.sibling,不会 append 嵌套的,嵌套的会在他自己是 workInProgress 时 append

finalizeInitialChildren 初始化属性,初始化事件监听

  • 事件监听初始化
  • 执行 setInitialProperties
  • 返回 shouldAutoFocusHostComponent 告知是否需要 auto focus
  • switch 必要标签的操作
  • 绑定事件 trapBubbledEvent, 区分事件类型实现不同的事件绑定
  • input option select textarea 交互组件有不同的操作
  • 执行 setInitialProperties 对应不同标签绑定事件
  • 再执行 setInitialDOMProperties
// ...
  setInitialDOMProperties(
    tag,
    domElement,
    rootContainerElement,
    props,
    isCustomComponentTag,
  );
  • setInitialDOMProperties 设置属性和事件绑定
  • ensureListeningTo 事件绑定
  • listenTo 进行绑定事件

HostComponent 更新 DOM 时进行的 diff 判断

updateHostComponent

diffProperties

  • 根据不同的节点做不同的操作
  • 生成 updatePayload 赋值给 workInProgress.updateQueue
  • 最后标记 workInProgress.effect = UPDATE
  • 虚拟 dom 就是根据 props 描述生成的 dom 对象
  • 根据不同标签节点提取新老 props 准备比较
  • 第一次遍历老 props 把要删除的属性都设置为 null
  • 第二次遍历新 props
  • 比较 style 样式对象, 最后(updatePayload = updatePayload || []).push(STYLE, styleUpdates);
  • 最后 return updatePayload: [k1,v1,k2,v2,k3,v3] 的属性

completeWork 对于 HostText 的更新

  • 核心是 document.createTextNode

renderRoot 错误处理

核心

  • 给报错的节点增加 Incomplete 副作用 effect
  • 给父链上具有 error boundary 的节点增加副作用
  • 创建错误相关的更新

onUncaughtError

  • 致命错误设置为 NoWork,不构建 effect 链
  • nextFlushedRoot.expirationTime = NoWork; 取消当前 root 的更新

throwException

  • 错误处理 给报错节点组件 增加 Incomplete effect,
  • 清空报错节点的 effect 链
  • suspened 异步组件抛出的 promise
  • 构建错误对象

throwException 处理错误节点

  • 向上遍历 class 组件找可以处理错误的 class 组件生命周期
  • 一直找到 Root 节点执行内置错误处理
  • 给能处理错误的节点组件的 effect 都加了 ShouldCapture
  • 创建错误更新,入 workInProgress.updateQueue 更新队列来更新
  • getDerivedStateFromError 生命周期直接赋值在 update.payload 上
  • componentDidCatch 生命周期作为 callback 处理
  • createClassErrorUpdate 创建 class 组件处理错误的 update
  • createRootErrorUpdate 创建 root 节点处理错误的 update
  • 最后 enqueueCaptureUpdate,类似 enqueueUpdate 交给 react 更新

completeUnitOfWork 处理报错节点

  • 报错的节点直接进入 completeUnitOfWork 完成
  • 不渲染子节点
  • 报错节点在 completeUnitOfWork 内走 unwindWork 流程


unwindWork 的处理

  • 类似 completeWork 对不同组件进行处理
  • 对 shouldCapture 组件设置 DidCapture effect 副作用
  • 大部分没动作, 其余也多是 pop context
  • 只有 HostComponent, HostText, SuspenseComponent 有操作
  • 与 completeWork 最大的区别就是会判断 ShouldCapture
  • throwException 处理错误节点时给能处理错误的节点组件的 effect 都加了 ShouldCapture


当前报错组件能处理错误重新标记 effect

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

推荐阅读更多精彩内容