Mike K
Mike K

Reputation: 6511

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

Upvotes: 0

Views: 1125

Answers (2)

Dmitry Nikulin
Dmitry Nikulin

Reputation: 46

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.

Upvotes: 2

Fried noodles
Fried noodles

Reputation: 125

That's because your current[0] is in fact an object with a .current key inside it, you can get the value you want by simply editing your heightOfFirstDiv to show that key

 const heightOfFirstDiv = refsArray.current[0].current.offsetHeight;

If you notice, on the example you tried to replicate you'll see they destructured this .current key, that's where the mistake came from

Upvotes: 1

Related Questions