useEffect和useLayoutEffect执行时机

流程

  1. react在diff之后,会进入commit阶段,将新生成的虚拟DOM发生的变化映射到真实DOM上
  2. 在commit的前期,会调度一些生命周期方法,对于类组件来说,会触发getSnapshotBeforeUpdate。对于函数组件来说,会调度useEffect。
  3. 但是并不是立即执行,在此阶段,会把useEffect入列到react维护的调度队列中,给一个普通的优先级,异步执行。
  4. 之后,在将新生成的虚拟DOM发生的变化映射到真实DOM上的过程中,会通过commitWalk根据不同的fiberNode进行DOM修改。
  5. 当commitWalk遇到类组件时,不会进行任何操作,因为没有真实的dom节点,直接return,处理下一个节点
  6. 但对于有了hooks的函数组件来说,会同步调用上一次渲染时useLayoutEffect函数的destroy方法
  7. 注意节点在commitWalk后,变化已经被映射到真实的DOM上了
  8. 但是由于JS线程和渲染线程是互斥的,真实的DOM虽然已经改变了,浏览器却没有立刻渲染到屏幕上
  9. 此时会同步执行对应的生命周期方法,如componentDidmount、componentDidUpdate以及useLayoutEffect的create方法。此时如果对DOM进行了操作,会一起处理
  10. 在react中,commit不会被打断,直至所有节点都commit结束,react更新完成,JS才停止执行
  11. 浏览器此时才会进入渲染线程,将发生变化的DOM渲染到屏幕上,因此react只用了一次回流、重绘的代价,将所有需要更新的DOM节点更新了
  12. 浏览器渲染完成后,react开始之前之前提到的调度队列,才开始执行useEffct产生的函数

一些结论

  1. useEffect的create函数,调用时机和位置都与componentDidMount,componentDidUpdate 一致,且都是被 React 同步调用,都会阻塞浏览器渲染。

  2. 将对DOM的操作放在useLayoutEffect中,性能更好

原文地址:https://www.cnblogs.com/ashen1999/p/14894741.html