一、理论
-
useEffect:使用频率较高,异步执行,即在渲染成dom之后执行。(避免在此过程中进行复杂的dom操作的立即执行行为)
过程:首次/重新渲染 => react行为 => 真实dom更新 => useEffect
-
useLayoutEffect:使用场景需要进行判断,多数用于解决dom元素闪屏问题。
过程:首次/重新渲染 => react行为 => useLayoutEffect => 真实dom更新
-
在大多数情况下,effect会在对应的依赖项如state或props改变时执行,而对应的回调逻辑往往不会立即影响或根本不影响页面视觉。(ajax、event emitter)
-
大多数时候,使用useEffect是正确的。如果您的代码导致闪烁,切换到useLayoutEffect。
-
因为useLayoutEffect是同步的,也就是阻塞的,在你的effect运行完之前,视觉不会更新。如果你的effect中有计算密集型代码,它可能会导致性能体验问题,比如卡顿。大多数effect在运行时并不需要"stop the world",普通的 useEffect几乎可以满足我们所有的需求。
二、根本原因
-
同步执行对应的生命周期方法,我们说的componentDidMount,componentDidUpdate 以及 useLayoutEffect(create, deps),浏览器渲染线程依旧处于被阻塞阶段,所以还没有发生回流、重绘过程。由于内存中的 DOM 已经被修改,通过 useLayoutEffect 可以拿到最新的 DOM 节点,并且在此时对 DOM 进行样式上的修改,假设修改了元素的 height,这些修改会在步骤 11 和 react 做出的更改一起被一次性渲染到屏幕上,依旧只有一次回流、重绘的代价。
-
如果放在 useEffect 里,useEffect 的函数会在组件渲染到屏幕之后执行,此时对 DOM 进行修改,会触发浏览器再次进行回流、重绘,增加了性能上的损耗。