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

React中useRef数组访问元素返回undefined问题排查

问题根源分析与修复方案

你的代码里有几个关键问题导致refs访问返回undefined,咱们一步步拆解清楚:

1. 把React元素存入state是反模式

你通过items.map生成的<div>元素被存入了renderedItems state,这不符合React的设计逻辑。React元素应该直接在组件的渲染阶段(也就是return语句里)生成,而不是存在state中。这种做法会触发不必要的组件重渲染,还会打乱ref绑定与组件更新的同步节奏。

2. 对createRef的使用存在误解

你用React.createRef()创建的是一个带有current属性的容器对象,不是直接指向DOM节点。你原来的代码里直接访问refsArray.current[0].offsetHeight,但refsArray.current[0]只是这个空容器,它本身没有offsetHeight属性,自然返回undefined——正确的访问方式应该是refsArray.current[0].current.offsetHeight,而且只有当DOM节点挂载完成后,current才会指向真实的div元素。

3. useEffect与ref绑定的时机不匹配

你的第一个useEffect依赖renderedItems,当调用setRenderedItems后这个effect会立刻执行,但此时React还没把新生成的<div>挂载到DOM上,createRef的current属性还没被赋值,所以即使你补了.current,拿到的依然是undefined。

4. ref数组的初始化方式不够可靠

在仅执行一次的useEffect里给refsArray赋值createRef,当组件后续因其他原因重渲染时,这个逻辑不会再执行,万一数组长度变化或者组件重新挂载,ref绑定会出现混乱。回调ref是处理多ref场景更可靠的方案。


修复后的完整代码

import React from "react";
const items = [ [1, 2, 3, 4, 5], [6, 7, 8, 9, 10] ];

export default function Component() {
  const [height, setHeight] = React.useState(0);
  const refsArray = React.useRef([]);

  // 用回调ref同步DOM节点与refs数组
  const setRef = (element, index) => {
    refsArray.current[index] = element;
  };

  React.useEffect(() => {
    // 先判断DOM节点是否存在,避免挂载前访问报错
    const firstDiv = refsArray.current[0];
    if (firstDiv) {
      const heightOfFirstDiv = firstDiv.offsetHeight;
      console.log("heightOfFirstDiv", heightOfFirstDiv);
      setHeight(heightOfFirstDiv);
    }
  }, []); // 如果items是动态变化的,记得把items加入依赖数组

  return (
    <div>
      The height is: {height || "undefined"}
      {/* 直接在渲染阶段生成列表元素,用回调ref绑定 */}
      {items.map((item, index) => (
        <div 
          key={index} // 列表渲染必须加key,这是React的强制要求
          ref={(el) => setRef(el, index)} 
          style={{ height: 100, width: 40 }}
        >
          {item}
        </div>
      ))}
    </div>
  );
}

关键修复点说明

  • 移除了renderedItems state:直接在return里通过items.map生成元素,回归React正常的渲染流程。
  • 改用回调ref:回调函数会在DOM节点挂载/卸载时自动触发,确保refs数组始终与真实DOM节点同步,而且不需要再处理createRef的current属性,直接拿到DOM元素。
  • 添加了key属性:列表渲染必须加唯一key,避免不必要的重渲染和React警告。
  • 增加存在性检查:在useEffect里先判断DOM节点是否存在,避免组件挂载前访问ref导致的报错。

如果你的items是动态更新的,记得把items添加到useEffect的依赖数组中,这样当列表内容变化时,能重新获取最新的DOM高度。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 07:26:15