react17源码解读-commit阶段

commitRoot是commit的起点,fiberRootNode会作为传参commitRoot(root)

做了什么操作

  • 执行副作用: 在rootFiber.firstEffect上保存了一条需要执行副作用的fiber节点的单向链表effectList,这些节点的updateQueue中保存了变化的props(props是一个数组)这些副作用都会在commit阶段执行。
  • 一些生命周期函数、hook、需要在commit阶段执行。

commit工作流程主要分为三部分

before mutation DOM操作前

主要是做一些变量赋值、状态重置工作。

  1. 将effectList赋值给firstEffect,由于每个fiber的effectList只包含他的子孙节点,所以根节点如果有effectTag则不会被包含进来,所以将有effectTag的根结点插到effectList的尾部,这样保证有effect的fiber在effectList中,遍历effectList。
  2. 调用commitBeforeMutationEffects,
    函数中处理了
    a. dom渲染后的autoFocus、blur逻辑
    b. 调用getSnapShotBeforeUpdate生命周期
    c. 异步调度useEffect(与优先级有关,防止同步执行阻塞浏览器渲染,useLayoutEffect是同步的)
* 异步调度useEffect分为三部:
1. before mutation阶段 在scheduleCallback中调度flushPassiveEffects。
2. layout阶段之后将effectList赋值给rootWithPendingPassiveEffects。  
3. scheduleCallback触发flushPassiveEffects,flushPassiveEffects内部遍历rootWithPendingPassiveEffects
mutation DOM操作

遍历effectList,执行commitMutationEffects,commitMutationEffects主要是对每个fiber进行视图的操作,包括:文字节点处理、ref处理、根据effectTag对组件增删改查。

ps1:如果是dom元素的更新操作会相应处理style、dangerouslySetInnerHTML、children等属性
ps2: 更新操作会触发useLayoutEffect的销毁函数
ps3: 如果删除组件操作,会调用对应的useEffect销毁函数或componentWillUnMount
layout DOM渲染完成后

主要完成了 useEffect相关处理,性能追踪,一些生命周期钩子(componentDidxxx)、hook(useLayoutEffect\useEffect),赋值ref等

遍历effectList,执行commitLayoutEffects。

function commitLayoutEffects(root: FiberRoot, committedLanes: Lanes) {
  while (nextEffect !== null) {
    const effectTag = nextEffect.effectTag;
    // 调用生命周期钩子和hook
    if (effectTag & (Update | Callback)) {
      const current = nextEffect.alternate;
      commitLayoutEffectOnFiber(root, current, nextEffect, committedLanes);
    }
    // 赋值ref
    if (effectTag & Ref) {
      commitAttachRef(nextEffect);
    }
    nextEffect = nextEffect.nextEffect;
  }
}

commitLayoutEffectOnFiber

  1. 根据current===null判断是mount还是update,调用componentDidMount或者componentDidUpdate。
  2. 触发setState的回调函数
  3. 调用useLayout的回调(同步的),调度useEffect的销毁与回调(异步的)。

因为双缓存机制,需要切换fiber树,这个操作在mutation前,layout后执行

root.current=finishedWork

因为componentWillUnmount会在mutation阶段执行,current Fiber树指向更新前的fiber树,在生命周期钩子内获取的dom是更新前的。
componentDidMount和componentDidUpdate会在layout阶段执行,current Fiber树指向更新后的fiber树,生命周期内获取到的DOM是更新后的。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容