示例:在获取指定元素的高度时,始终打印为0
原因:可能是页面渲染过慢,造成offsetHeight(offsetWidth、clientHeight…)等属性渲染不及时
const { useState, useRef } from 'react'
const [height, setHeight] = useState(0) // 元素的高
const divRef = useRef() // 定义绑定到元素上的ref对象
const heightRef = useRef(0) // 记录绑定ref的元素高度
<div ref={divRef}>
......
</div>
解决方法有以下几种:
1 使用useEffect监听offsetHeight属性的改变,然后赋值(不推荐)
useEffect(() => {
setHeight(divRef.current?.offsetHeight)
}, [divRef.current?.offsetHeight])
2 使用计时器监听offsetHeight,有改变即重新赋值
useEffect(() => {
const timer = setInterval(() => {
// offsetHeight没有改变终止当前循环
if (heightRef.current === divRef.current?.offsetHeight) return
// offsetHeight改变时,重新赋值
heightRef.current = divRef.current?.offsetHeight
setHeight(divRef.current?.offsetHeight)
}, 300)
return () => { // 离开页面时,卸载计时器
clearInterval(timer)
}
}, [])
3 使用web api(getBoundingClientRect)
Element.getBoundingClientRect()方法返回一个 DOMRect 对象,其提供了元素的大小及其相对于视口的位置,浏览器兼容性较好。
const { left, right, top, bottom, x, y, width, height } = divRef.current?.getBoundingClientRect()
结论:
不推荐第一种监听属性的方法,因为使用useEffect对一个复杂对象监听时,效果可能不太理想。