KylianMbappe
KylianMbappe

Reputation: 2397

DOM Element Returning Null on React

[EDIT] HAS BEEN FIXED (scroll to bottom)

Hi I am trying to select a react element for a functional component, current code:

const Emoji = (props) => {

  const copyButton = useRef(null);

  function handleHover(e) {
    console.log(this.copyButton); //want to select this element
  }

  function handleMouseOut(e) {

  }

  return(
    <div className="wrapper">
      <div id={"emoji-"+props.id} className="emoji" onMouseOver={handleHover} onMouseOut={handleMouseOut}>
        <Button ref={copyButton} className="copyButton" buttonText="Copy" buttonColour="primary" />
        <Button className="button" buttonText="Information" buttonColour=" " />
        <h1>{props.emojiCharacter}</h1>
        <p>{props.emojiName}</p>
      </div>
    </div>
  );
}

export default Emoji;

I am trying to build an app where when the user hovers over this component the buttons will appear, but when I try to select them I keep getting this error: TypeError: Cannot read property 'copyButton' of undefined

It also returns null when I try to document.getElementById as well.

Any suggestions? Thanks.

FIXED

The problem was due to the element being a custom component and not a default component, otherwise I could've simply just used copyButton.current

I fixed it by going into the component's jsx and changing the const Button = (props) => { etc } declaration to a

const Button = React.forwardRef((props, ref) => (
    <div ref={ref} 
    </div>
));

This article did it https://reactjs.org/docs/forwarding-refs.html

Upvotes: 2

Views: 1452

Answers (2)

phoenixstudio
phoenixstudio

Reputation: 2598

copyButton will not be ready on the first cycle of render you need to test before invoking it, and you will need to use copyButton.current

const handleMousehover =() =>{
  if(copyButton && copyButton.current){
   // add your code here
  }
}

You will not need to test if the hover is comming from where you used ref={copyButton}, but if it is comming from somewhere else, there is no garenty that it will not be null (or it became null for some reason), so it is a good practice to test it always.

Upvotes: 1

Imran Rafiq Rather
Imran Rafiq Rather

Reputation: 8088

You need to use copyButton.current to select your ref={copyButton} Button.

The useRef Hook is a function that returns a mutable ref object whose .current property is initialized with the passed argument (initialValue.)The returned object will persist for the full lifetime of the component.

const Emoji = (props) => {

  const copyButton = useRef(null);

  function handleHover(e) {
    console.log(copyButton.current); //want to select this element
  }

  function handleMouseOut(e) {

  }

  return(
    <div className="wrapper">
      <div id={"emoji-"+props.id} className="emoji" onMouseOver={handleHover} onMouseOut={handleMouseOut}>
        <Button ref={copyButton} className="copyButton" buttonText="Copy" buttonColour="primary" />
        <Button className="button" buttonText="Information" buttonColour=" " />
        <h1>{props.emojiCharacter}</h1>
        <p>{props.emojiName}</p>
      </div>
    </div>
  );
}

export default Emoji;

NOTE: Coming to the second part of the question. You will ned to set styles within your handleHover() function for show and hide logic.

Something like this :) Just a demo. Implement it as per your requirement

  function handleHover(e) {
    console.log(copyButton.current); 
    copyButton.current.style.display="block";
  }

Upvotes: 0

Related Questions