React自定义usePosition Hook中null属性读取错误的解决方法
解决usePosition Hook的null属性读取错误
自定义usePosition Hook实现元素位置对比居中对齐功能正常,但控制台反复出现以下错误:
Uncaught TypeError: Cannot read properties of null (reading 'offsetLeft') at getPosition (usePosition.js:18:1)
错误原因
当组件初始化、元素被条件渲染隐藏(比如下拉菜单处于disabled状态)时,elRef.current或elSecondRef.current会是null,此时调用getPosition直接读取其属性就会触发报错。
修改后的usePosition Hook代码
import { useEffect, useRef, useState } from "react"; const usePosition = () => { const elRef = useRef(); const elSecondRef = useRef(); // 给状态设置初始值,避免undefined引发额外问题 const [fromLeftEl, setFromLeftEl] = useState(0); const [fromTopEl, setFromTopEl] = useState(0); const [widthEl, setWidthEl] = useState(0); const [heightEl, setHeightEl] = useState(0); const [widthElSecond, setWidthElSecond] = useState(0); const [finalX, setFinalX] = useState(0); const [finalY, setFinalY] = useState(0); const getPosition = () => { // 核心修复:先判断元素是否存在,不存在直接终止函数 if (!elRef.current || !elSecondRef.current) return; const fromLeftEl = elRef.current.offsetLeft; setFromLeftEl(fromLeftEl); const fromTopEl = elRef.current.offsetTop; setFromTopEl(fromTopEl); const widthEl = elRef.current.offsetWidth; setWidthEl(widthEl); const heightEl = elRef.current.offsetHeight; setHeightEl(heightEl); const widthElSecond = elSecondRef.current.offsetWidth; setWidthElSecond(widthElSecond); const middleEl = widthEl / 2; const middleElSecond = widthElSecond / 2; const finalX = fromLeftEl + middleEl - middleElSecond; setFinalX(finalX); const finalY = fromTopEl + heightEl; setFinalY(finalY); }; useEffect(() => { getPosition(); }, []); useEffect(() => { window.addEventListener("resize", getPosition); window.addEventListener("click", getPosition); window.addEventListener("scroll", getPosition); // 修复清理函数:移除所有添加的事件监听,避免内存泄漏 return () => { window.removeEventListener("resize", getPosition); window.removeEventListener("click", getPosition); window.removeEventListener("scroll", getPosition); }; }, []); return { elRef, elSecondRef, fromLeftEl, fromTopEl, widthEl, heightEl, finalY, finalX, widthElSecond, getPosition // 暴露方法供外部触发重新计算 }; }; export default usePosition;
额外优化:下拉菜单切换时重新计算位置
在Nav组件中,下拉菜单切换显示状态时,需要手动触发位置计算,确保坐标正确:
- 在Nav组件中解构出
getPosition方法:
const { elRef, elSecondRef, finalY, finalX, getPosition } = usePosition();
- 修改
handleToggle方法:
const handleToggle = () => { setActive(!isActive); // 等待DOM更新完成后再计算位置 setTimeout(getPosition, 0); };
内容的提问来源于stack exchange,提问作者Zwirek_dev
相关产品推荐
相关产品推荐

