React 第十九节 useLayoutEffect 用途使用技巧注意事项详解
1、概述
useLayoutEffect
是useEffect
的一个衍生版本,只是他们的执行时机不同
useLayoutEffect
用于在DOM更新执行完成之后,浏览器渲染绘制之前执行
,这会阻塞浏览器的渲染;
useEffect
的执行时机是在组件首次渲染和更新渲染之后
异步执行的,这就意味着 useEffect
的执行并不会阻塞
组件的渲染,也不会影响到用户的交互体验;
由于useEffect
执行的的异步
操作,那么在其副作用函数中执行,数据请求、DOM操作、定时任务,即使有大量的计算耗时,也不会让用户感觉到界面卡顿现象
;
而useLayoutEffect
执行的是同步
操作,不适用于大量耗时的进程在副作用函数中执行,否则会是界面显的非常卡顿
,从而影响用户的体验感;
useEffect具体使用详情
2、写法
useLayoutEffect(setup, dependencies)
第一个参数:setup
,处理副作用
的函数,在将组件首次添加到 DOM 之前,React 将运行 setup 函数。在每次因为依赖项变更而重新渲染后,React 将首先使用旧值运行 cleanup 函数(如果你提供了该函数),然后使用新值运行 setup
函数。在组件从 DOM 中移除之前,React 将最后一次运行 cleanup
函数。
第二个参数:依赖项数组,与 useEffect的依赖项一样为可选项;
useLayoutEffect(() => {
console.log('=设置函数==')
// 用于根据依赖项变化而执行的逻辑
return () => {
// 清理函数,组件卸载移除时,执行的逻辑
}
},[name])
3、用法示例
当我们使用 useEffect
将一个圆形由直径 10px
,变大到 直径为200px
时;会看到 图形的变化整个过程;
而我们使用 useLayoutEffect
时,直接看到的就是 直接为 200px 的圆形,不会看到图片变化过程,给用户的感觉视图的白屏时间更长,体验不好;
/* index.less文件 */
.base-class{
display: block;
width: 10px;
height: 10px;
background-color: #f00;
border-radius: 50%;
position:relative;
}
.area-box{
width: 200px;
height: 200px;
}
3.1 使用 useEffect Hook
时,
是异步
执行,不会阻塞浏览器渲染,故可以看见图形变化过程;
import {useState, useEffect } from 'react'
import './index.less'
export default function MyLayoutEffect() {
const [area, setArea] = useState(false)
const handleChangeArea = () => {
setArea(false)
}
// 使用时间延迟
let now = performance.now()
while (performance.now() - now < 200) {}
useEffect(() => {
setArea(true)
}, [area])
return (
<div>
<span className={area ? 'base-class area-box' : 'base-class'}>useEffect圆的面积</span>
<hr />
<p>areaLayout:---{areaLayout}----</p>
<hr />
<button onClick={handleChangeArea}>改变圆形面积</button>
</div>
)
}
3.2、使用 useLayoutEffect
时,
无论我们是点击按钮改变原型大小,还是初次加载,屏幕中始终的 直径为 200px 的圆形;这是因为 useLayoutEffect
的状态更新,会在屏幕渲染之前执行,进而导致阻塞渲染,而一直看到都是大图
import {useState, useLayoutEffect} from 'react'
import './index.less'
export default function MyLayoutEffect() {
const [areaLayout, setAreaLayout] = useState(false)
const handleChangeArea = () => {
setAreaLayout(false)
}
let now = performance.now()
while (performance.now() - now < 200) {}
useLayoutEffect(() => {
setAreaLayout(true)
}, [areaLayout])
return (
<div>
<p>areaLayout:---{areaLayout}----</p>
<span className={areaLayout ? 'base-class area-box' : 'base-class'}>useLayoutEffect</span>
<hr />
<hr />
<button onClick={handleChangeArea}>改变圆形面积</button>
</div>
)
}
4、使用场景
1、需要在屏幕渲染完成之前 获取元素DOM的位置尺寸,同步进行调整
2、防止闪屏,因useLayoutEffect
会在浏览器渲染前
计算好 元素的位置大小,故不会像 useEffect,会看见视图元素 位置大小变化过程,但是如果时间过短,会给用户一种闪屏的错觉
;