美文网首页
react17源码解读-commit阶段

react17源码解读-commit阶段

作者: Mr无愧于心 | 来源:发表于2022-02-23 09:57 被阅读0次

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是更新后的。

相关文章

网友评论

      本文标题:react17源码解读-commit阶段

      本文链接:https://www.haomeiwen.com/subject/tlbacrtx.html