``
区别:
执行时机不同:
useLayoutEffect:DOM 发生了改变之后,浏览器绘制之前执行的
useEffect: 浏览器完成渲染之后
执行过程不同:
useLayoutEffect 同步执行,阻塞浏览器重新绘制 ,可能会导致页面渲染的卡顿
useEffect 异步执行,二次渲染问题,不阻塞浏览器绘制
执行顺序:
useLayoutEffect【微任务】 在 useEffect【宏任务】 之前执行
为什么会二次渲染:
产生二次渲染问题,第一次渲染的是旧的状态,接着下一个事件循环中,执行改变状态的函数,组件又携带新的状态渲染,在视觉上,就是二次渲染。
useEffect 的回调函数是【异步宏任务】,在下一轮事件循环才会执行。根据 JS 线程与 GUI 渲染线程互斥原则,在 JS 中页面的渲染线程需要当前事件循环的宏任务与微任务都执行完,才会执行渲染线程,渲染页面后,退出渲染线程,控制权交给 JS 线程,再执行下一轮事件循环。
如下图:拿这个代码跑一遍就可以复现二次渲染了
import { useCallback, useEffect,useLayoutEffect, useState } from 'react';
export default () => {
const [num, setNum] = useState(Math.random())
useEffect(() => {
console.log(num,'11')
if (num === 0) {
setNum(Math.random())
}
}, [num])
return (
<>
<h1>num 的值是:{num}</h1>
<button onClick={() => setNum(0)}>重置 num</button>
</>
)
}
由下图中可以看到使用useEffect,num先是变为了0,在变成的随机数,二次渲染。 而useLayoutEffect,直接变成随机数,没有二次渲染问题。