概述

  • React创建的应用程序分两部分,一部分是首次创建的Mount阶段,另一部分是常见的更新更新和事件触发阶段Update阶段。
  • 关于DOM更新是两套流程,首次创建和DOM更新。
  • 简述React中Class组件生命周期的运行时间点和HOOK组件中UseEffect、UseLayout的运行时间点

Render阶段

  • Render阶段又分beginWork阶段和complete阶段
  • Render阶段主要的目的是为每一个HTML节点生成Fibre节点,需要执行的事件也会挂载到Fibre节点上, 并根据页面结构生成Fibre链表
  • Render阶段生成Fibre链表结束后,交给commit阶段。commit阶段会在此基础上执行事件、渲染或更新DOM,最后绘制到页面上。

    beginWork阶段——创建Fibre节点

  • 在这个阶段会更根据页面的HTML结构和HTML元素生成创建对应的Fibre对象,记录节点的相关信息。如节点类型、节点上的属性、父级对象...
  • 在发生页面更新时,React会为每个元素重新构建一个新的Fibre对象。会在此阶段尝试复用上次的Fibre对象,如果没有发生改变就直接复制过来。
  • 会在此阶段调用shouldComponentUpdate生命周期函数,若调用该函数,则react页面在视觉上不会发生更新,但ref的引用还是会发生更新。

    complete阶段——创建虚拟DOM

  • beginWork生成Fibre对象后,在Complete方法中生成虚拟DOM。如果该Fibre节点有父级对象,则会将创建的虚拟DOM挂载到父级Fibre的属性中
  • 当执行到最后一个节点时,会得到一个虚拟DOM树,然后进入Commit阶段。

    Fibre对象和虚拟DOM的构建

    image.png

Commit阶段

  • React相关生命周期
    image.png
  • 处理Render阶段的Fibre链表,执行事件或更新DOM。
  • commit阶段分3部分,beforeMuation、Mutation、Layout。

    beforeMutaion阶段

    • 处理focus事件
    • 对于Class组件而言,处理getDerivedStateFromProps生命周期函数,可以控制本次更新过程中,页面能不能发生改变。
    • 对于HOOK而言,会将useEffect中的回调函数加入一个队列,会在整个Commit阶段完成以后再异步执行,而在本阶段并不会直接执行。
    • 调用Class组件的getSnapshotBeforeUpdate生命周期函数

Mutation阶段

  • Mutation阶段会遍历包含useEffecTarget属性t的Fibre链表,有需要文本更新的就更新,有需要更新ref的就更新ref。
  • 对DOM节点进行增删改查的操作。处理结果会反馈到Fibre节点中(如新增fibre节点,删除fiebr节点),这个Fibre节点并不一定是当前Fibre节点,也可能是当前Fibre节点的父级。
  • 对于当前Fibre节点发生更新的情况,若是HOOK组件,会调用useLayoutEffect的销毁函数;对于Class组件而言,会调用componentDidWillUnMount生命周期函数。如果当前Fibre节点类型不是HOOK或Class类型,如div类型、span类型...就不会执行销毁函数的回调。(PS:更新后的结果必须保证上一次的销毁函数调用)
  • Mutation阶段的current指针还是之前的,所以执行销毁函数的回调没有问题。

layout阶段

  • layout阶段会替换current指针,这就是双缓存机制发生变更的时间点。
  • layout阶段会根据current指针是否有值,执行不同的生命周期函数。没有值,执行Class组件的componentDidMount生命周期;有值就执行componentDidUpdate生命周期函数
  • 对于HOOK而言,会调用useEffect的回调函数,将销毁函数加入到队列中。本阶段的最后会检查这个队列,如果有的话会执行队列任务,直到清空后才算完成layout阶段。
  • this.setState()的回掉函数,也就是第二个参数,也是在这个阶段执行。
  • 会执行useLayoutEffect的回调函数,并将新的销毁函数添加到一个队列中。再次更新时,Mutation阶段就会执行UseLayout的销毁函数。

冷咖啡
22 声望3 粉丝

知识的搬运工😄