首页 > 解决方案 > Accessing any element in a useRef is throwing 'undefined'

问题描述

I'm trying to use a ref in React, which is an array that contains references to multiple other divs in the DOM.

In a useEffect, I map through an object to render the divs, and I assign a ref to each div. Before assigning the ref, I instantiate a slot for it with createRef.

I'm essentially trying to replicate what this answer has suggested doing.

The issue that I'm running into is that my compiler keeps seeing undefined. I'm not sure why this is happening, but here is the code that I have:

import React from "react";

const items = [
  [1, 2, 3, 4, 5],
  [6, 7, 8, 9, 10]
];
export default function Component() {
  const [renderedItems, setRenderedItems] = React.useState();
  const [height, setHeight] = React.useState(0);
  const refsArray = React.useRef([]);

  React.useEffect(() => {
    const heightOfFirstDiv = refsArray.current[0].offsetHeight;
    console.log("heightOfFirstDiv", heightOfFirstDiv); // <-- this is always undefined
    setHeight(heightOfFirstDiv);
  }, [renderedItems]);

  React.useEffect(() => {
    setRenderedItems(
      items.map((item, index) => {
        refsArray.current[index] = React.createRef();

        return (
          <div
            ref={refsArray.current[index]}
            style={{ height: 100, width: 40 }}
          >
            {item}
          </div>
        );
      })
    );
  }, []);

  return (
    <div>
      The height is: {height || "undefined"}
      {renderedItems}
    </div>
  );
}

What am I doing wrong here?

awesome-thompson-110v2

标签: javascriptreactjs

解决方案


The second answer to the question you have linked is better and simpler, actually. This can be implemented via callback refs:

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([]);

  React.useEffect(() => {
    const heightOfFirstDiv = refsArray.current[0].offsetHeight;
    console.log("heightOfFirstDiv", heightOfFirstDiv);
    setHeight(heightOfFirstDiv);
  }, [renderedItems]);

  const renderedItems = items.map((item, index) => (
    <div
      ref={(el) => (refsArray.current[index] = el)}
      key={index}
      style={{ height: 100, width: 40 }}
    >
      {item}
    </div>
  ));

  return (
    <div>
      The height is: {height || "undefined"}
      {renderedItems}
    </div>
  );
}

Storing rendered elements in component state is not a good practice, as it makes components complicated, confusing and hard to debug.


推荐阅读