我有一个钩子getBoundingClientRect
它捕获了 ref DOM 元素的对象。问题是,在第一次渲染时,它返回null
并且我只需要在组件上的第一次渲染时获取值。
我在功能组件中像这样使用它:
const App = () => {
// create ref
const rootRef = useRef(null);
// get Client Rect of rootRef
const refRect = useBoundingClientRect(rootRef);
useEffect(()=> {
// return "null" the first time
// return "DOMRect" when refRect is update
console.log(refRect)
}, [refRect])
return <div ref={rootRef} >App</div>
}
这里是 useBoundingClientRect 钩子,我在 App Component 中调用。
export function useBoundingClientRect(pRef) {
const getBoundingClientRect = useCallback(() => {
return pRef && pRef.current && pRef.current.getBoundingClientRect();
}, [pRef]);
const [rect, setRect] = useState(null);
useEffect(() => {
setRect(getBoundingClientRect());
},[]);
return rect;
}
问题是我想在 init 上缓存 boundingClientRect 对象,而不是第二次重新渲染组件:
// App Component
useEffect(()=> {
// I would like to get boundingClientRect the 1st time useEffect is call.
console.log(refRect)
// empty array allow to not re-execute the code in this useEffect
}, [])
我查看了一些教程和文档,发现有些人使用useRef
而不是useState
钩子来保持价值。所以我尝试在我的useboundingClientRect
钩子中使用它来捕获并返回 boundingClientRect 值在我的应用程序组件的第一个渲染时。它有效...部分地:
export function useBoundingClientRect(pRef) {
const getBoundingClientRect = useCallback(() => {
return pRef && pRef.current && pRef.current.getBoundingClientRect();
}, [pRef]);
const [rect, setRect] = useState(null);
// create a new ref
const rectRef = useRef(null)
useEffect(() => {
setRect(getBoundingClientRect());
// set value in ref
const rectRef = getBoundingClientRect()
},[]);
// return rectRef for the first time
return rect === null ? rectRef : rect;
}
现在,应用程序组件中的console.log(rectRef)
允许在第一次渲染时访问该值:
// App Component
useEffect(()=> {
console.log(refRect.current)
}, [])
但是如果我尝试从钩子返回refRect.current
useBoundingClientRect
返回null
.(什么?!
如果有人能向我解释这些错误。提前感谢!
您需要在此处了解引用、突变和更新的异步性质。
首先,当您使用 state 来存储clientRect
属性时,当您的自定义挂钩运行时useEffect
,它会在 state 中设置值,该值将反映在下一个渲染周期中,因为状态更新是异步的。这就是为什么在第一次渲染时您会看到undefined
.
其次,当你返回rectRef
时,你实际上是在返回一个对象,当useBoundingClientRect
中的useEffect
运行时,你稍后会在其中发生变异。数据在useEffect
运行之前返回,因为它在呈现周期之后运行。现在,当组件中的useEffect
运行时,即在自定义挂钩中的useEffect
运行之后,数据已经存在,并且已通过前一个useEffect
在其引用处进行了更新,因此您会看到正确的数据。
最后,如果您返回现在不可变值的rectRef.current
,则自定义钩子会更新该值,但自上一个引用null
以来,会在新的引用处更新该值,因此您看不到组件useEffect
方法的变化。