You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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组件中,下拉菜单切换显示状态时,需要手动触发位置计算,确保坐标正确:

  1. 在Nav组件中解构出getPosition方法:
const { elRef, elSecondRef, finalY, finalX, getPosition } = usePosition();
  1. 修改handleToggle方法:
const handleToggle = () => {
  setActive(!isActive);
  // 等待DOM更新完成后再计算位置
  setTimeout(getPosition, 0);
};

内容的提问来源于stack exchange,提问作者Zwirek_dev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 03:35:29