React源码解析:简述React 16 版本中 commit 阶段的三个子阶段分别做了那些事?

(1)before mutation阶段(执行DOM操作前):处理类组件的getSnapShotBeforeUpdate 生命周期函数

  1. 处理DOM节点渲染/删除后的 autoFocus、blur逻辑;
  2. 调用getSnapshotBeforeUpdate生命周期钩子;
  3. 调度useEffect。

(2)mutation阶段(执行DOM操作):将 workInProgress Fiber 树变成 current Fiber 树

  • 如果该fiber类型是ClassComponent的话,执行getSnapshotBeforeUpdate生命周期api,将返回的值赋到fiber对象的__reactInternalSnapshotBeforeUpdate上;
  • 如果该fiber类型是FunctionComponent的话,执行hooks上的effect相关 API。

代码层面:

  1. 根据ContentReset effectTag重置文字节点;
  2. 更新ref;
  3. 根据effectTag分别处理,其中effectTag包括(Placement | Update | Deletion | Hydrating);
  4. Placement时:获取父级DOM节点。其中finishedWork为传入的Fiber节点获取Fiber节点的DOM兄弟节点根据DOM兄弟节点是否存在决定调用parentNode.insertBefore或parentNode.appendChild执行DOM插入操作;
  5. Update时:执行所有useLayoutEffect hook的销毁函数。调用commitWork;6.Deletion时:递归调用Fiber节点及其子孙Fiber节点中fiber.tag为ClassComponent的componentWillUnmount
    (opens new window)生命周期钩子,从页面移除Fiber节点对应DOM节点解绑ref调度useEffect的销毁函数。

(3)layout(执行 DOM 操作后):commitHookEffectList()阶段,调用类组件生命周期函数或者函数组件的钩子函数

重置 nextEffect,useEffect是让FunctionComponent产生副作用的hooks,当使用useEffect后,会在fiber上的updateQueue.lastEffect生成effect链,具体请看ReactFiberHooks.js中的pushEffect()

作用:循环FunctionComponent上的effect链,并根据每个effect上的effectTag,执行destroy/create操作(作用类似于componentDidMount/componentWillUnmount)

代码层面:

  1. 调用componentDidxxx;
  2. 调用this.setState第二个参数回调函数;
  3. 调用useLayoutEffect hook的回调函数(与mutation的销毁函数是同步的),调度useEffect的销毁与回调函数(在before
    mutation只是先调度加入异步任务,在这里才真正执行),因此useLayoutEffect是同步的,useEffect是异步的;
  4. 获取DOM实例,更新ref5.current Fiber树切换(workInProgress Fiber树在commit阶段完成渲染后会变为current Fiber树)。

猜你喜欢

转载自blog.csdn.net/weixin_40599109/article/details/112581346