useLayoutEffect 介绍
官方提示:
- 如果你正在将代码从 class 组件迁移到使用 Hook 的函数组件,则需要注意
useLayoutEffect
与componentDidMount
、componentDidUpdate
的调用阶段是一样的。- 但是,我们推荐你一开始先用
useEffect
,只有当它出问题的时候再尝试使用useLayoutEffect
。
-
其函数签名与
useEffect
相同,只是调用时机不同。 -
useEffect
: 会在浏览器渲染绘制结束后执行 -
useLayoutEffect
: 则是在 DOM 更新完成后,浏览器绘制之前执行。
在react
完成DOM
更新后马上同步调用的代码,所以会阻塞页面渲染。 -
官方建议优先使用
useEffect
- 注意事项:
如果你使用服务端渲染:
请记住,无论 useLayoutEffect() 还是 useEffect() 都无法在 Javascript 代码加载完成之前执行。
这就是为什么在服务端渲染组件中引入 useLayoutEffect() 代码时会触发 React 告警。
解决这个问题,需要将代码逻辑移至 useEffect() 中(如果首次渲染不需要这段逻辑的情况下),
或是将该组件延迟到客户端渲染完成后再显示(如果直到 useLayoutEffect() 执行之前 HTML 都显示错乱的情况下)
- 解决方法:
若要从服务端渲染的 HTML 中排除依赖布局 effect 的组件,
可以通过使用 showChild && <Child /> 进行条件渲染,
并使用 useEffect(() => { setShowChild(true); }, []) 延迟展示组件。
这样,在客户端渲染完成之前,UI 就不会像之前那样显示错乱了。
useLayoutEffect 对比
- 先按照 gsap 动画插件
npm i -S gsap
index.css
文件
.animate {
position: relative;
top: 0;
left: 0;
width: 800px;
height: 400px;
border: 1px solid red;
}
.squ {
position: absolute;
top: 0;
left: 0;
width: 100px;
height: 100px;
background: green;
}
App.jsx
文件(useEffect)
import React, { useEffect, useLayoutEffect, useRef } from "react";
import gsap from "gsap";
import './index.css';
const App = () => {
const REl = useRef(null);
useEffect(() => {
/*下面这段代码的意思是当组件加载完成后,在0秒的时间内,将方块的横坐标位置移到600px的位置,会闪动*/
gsap.to(REl.current, 0, { x: 600 })
}, []);
return (
<div className='animate'>
<div ref={REl} className="square">square</div>
</div>
);
};
export default App
App.jsx
文件(useLayoutEffect)
import React, { useEffect, useLayoutEffect, useRef } from "react";
import gsap from "gsap";
import './index.css';
const App = () => {
const REl = useRef(null);
useLayoutEffect(() => {
/*下面这段代码的意思是当组件加载完成后, 方块的横坐标位置直接出现在600px的位置*/
gsap.to(REl.current, 0, { x: 600 })
}, []);
return (
<div className='animate'>
<div ref={REl} className="square">square</div>
</div>
);
};
export default App