React 中 useEffect 和 useLayoutEffect 作用和区别
日常开发中的大部分情况下,使用 useEffect 就可以帮我们处理组件的副作用,但是如果想要同步调用一些副作用,比如对 DOM 的操作,就需要使用 useLayoutEffect,useLayoutEffect 中的副作用会在 DOM 更新之后同步执行,useLayoutEffect 与原来 class 组件原来的 componentDidMount & componentDidUpdate 一样,会在 react 完成 DOM 更新后马上同步调用的代码,会阻塞页面渲染。
下面的例子中,useLayoutEffect 会在 render,DOM 更新之后同步触发函数,会优于 useEffect 异步触发函数。
function Demo() {
const [width, setWidth] = useState(0);
useLayoutEffect(() => {
const title = document.querySelector("#title");
const titleWidth = title.getBoundingClientRect().width;
console.log("useLayoutEffect");
if (width !== titleWidth) {
setWidth(titleWidth);
}
});
useEffect(() => {
console.log("useEffect");
});
return (
<div>
<h1 id="title">hello</h1>
<h2>{width}</h2>
</div>
);
}
官方建议优先使用 useEffect
在实际使用时如果想避免页面抖动(在useEffect里修改DOM很有可能出现)的话,可以把需要操作DOM的代码放在useLayoutEffect里。关于使用useEffect导致页面抖动,参考git仓库git仓库示例。
不过 useLayoutEffect 在服务端渲染时会出现一个warning,要消除的话得用useEffect代替或者推迟渲染时机。
服务端渲染(ssr)
在服务端渲染组件中引入 useLayoutEffect 代码时会触发 React 告警, 因为无论 useLayoutEffect 还是 useEffect 都无法在 Javascript 代码加载完成之前执行。要解决这个问题,需要将代码逻辑移至 useEffect 中(如果首次渲染不需要这段逻辑的情况下),或是将该组件延迟到客户端渲染完成后再显示(如果直到 useLayoutEffect 执行之前 HTML 都显示错乱的情况下)。
若要从服务端渲染的 HTML 中排除依赖布局 effect 的组件,可以通过使用 showChild &&