结论
useEffect: 在浏览器完成布局与绘制之后,传给useEffect的函数会延迟调用,也就是说如果在useEffect里有DOM相关操作,那么DOM变动后,会再次触发浏览器的绘制。useLayoutEffect:它会在所有的
DOM变更之后同步调用 effect,也就是说useLayoutEffect发生在DOM变更后,浏览器执行绘制之前。也就是说如果在useLayoutEffect里有DOM的相关操作,不会再次触发浏览器的绘制。
案例证明
-
相关代码
const ref = useRef<HTMLDivElement>(null); useEffect(() => { // 刷新有过渡动画 ref.current!.style.left = '600px'; }); useLayoutEffect(() => { // 刷新没有过渡动画 // ref.current!.style.left = "600px"; }); console.time("a"); console.timeEnd("a"); return ( <div className="compare-effect"> <div className="container"> <div className="box" ref={ref}></div> </div> </div> );.compare-effect { height: 100%; display: flex; align-items: center; justify-content: center; } .container { height: 50px; width: 700px; background-color: aqua; position: relative; } .box { height: 50px; width: 50px; background-color: red; position: absolute; top: 0; left: 0; transition: left 3s; } -
分析
一段简单的过渡动画demo。初始位置在左侧0,目标位置在600。
如果把box改变位置的代码放在useEffect里,浏览器会有一个初始位置的绘制以及改变后的绘制,所以会产生过渡动画。
如果把box改变位置的代码放在useLayoutEffect里,此时浏览器只会绘制改变DOM之后的结果,所以不会产生过渡动画。