Reputation: 2397
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.
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
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
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