Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Correct way to pass useRef hook to ref property

I'm not sure how to formulate the question less vaguely, but it's about pass-by-value and pass-by-reference cases in react. And Hooks.

I am using gsap to animate a div slide-in and out is the context for this, but I'm going to guess that what the ref is used for shouldn't matter.


So, this works fine, even though this is a more class-component-typical way of passing a ref as i understand it:

const RootNavigation = () => {
var navbar = useRef();

const myTween = new TimelineLite({ paused: true });    
const animate = () => {
    myTween.to(navbar, 0.07, { x: "100" }).play();
  };

return(
     <div className="nav-main" ref={div => (navbar = div)}>   // <<<<<<<<<<   pass as a callback
     ...
    </div>
    )}

And this elicits a "TypeError: Cannot add property _gsap, object is not extensible" error, even though this is how the React Hooks guide would have me do it:

const RootNavigation = () => {
var navbar = useRef();

const myTween = new TimelineLite({ paused: true });    
const animate = () => {
    myTween.to(navbar, 0.07, { x: "100" }).play();
  };

return(
     <div className="nav-main" ref={navbar}>          //<<<<<<<<<<<<<  not passing a callback
     ...
    </div>
    )}

Could somebody explain to me what's going on here or even toss a boy a link to where it's already been explained? I'm sure some sort of Dan character has written about it somewhere, i'm just not sure what to google. Thank you!

like image 417
rtviii Avatar asked Dec 23 '19 02:12

rtviii


People also ask

How do you pass reference props in React hooks?

We create a React ref by calling React.createRef and assign it to a ref variable. We pass our ref down to <FancyButton ref={ref}> by specifying it as a JSX attribute. React passes the ref to the (props, ref) => ... function inside forwardRef as a second argument.

How do I store a useRef hook?

Storing element references with useRef To do this, create the ref, and then pass it into the element: const Component = () => { const ref = useRef(null); return <div ref={ref}> Hello world </div>; }; With this reference, you can do lots of useful things like: Grabbing an element's height and width.

How do you ref in Hook?

In order to work with refs in React you need to first initialize a ref which is what the useRef hook is for. This hook is very straightforward, and takes an initial value as the only argument. This hook then returns a ref for you to work with.

How do you pass ref in functional components?

To create a ref in a functional component we use the useRef() hook which returns a mutable object with a . current property set to the initialValue we passed to the hook. This returned object will persist for the full lifetime of the component. Thus, throughout all of its re-rendering and until it unmounts.


1 Answers

In the first example you aren't using a ref, you are reassigning navbar through the ref callback so navbar is the DOM element.

It's the same as

let navbar = null;

return <div ref={node => (navbar = node)} />

In the second example you are using the ref object which is an object with a current property that holds the DOM element

const navbar = useRef(null)

return <div ref={navbar} />

navbar is now

{ current: the DOM element }

So you are passing the object into myTween.to() instead of the DOM element inside navbar.current

Now in the second example gsap is trying to extend the ref object itself and not the DOM element.

Why do we get the TypeError: Cannot add property _gsap, object is not extensible`?

If you look at the source code of useRef you will see on line 891

if (__DEV__) {
  Object.seal(ref);
}

that React is sealing the ref object and JavaScript will throw an error when we try to extend it using Object.defineProperty() which is probably what gsap is doing.

The solution for using a ref will be to pass ref.current into tween.to()

const RootNavigation = () => {
  const navbar = useRef()

  const myTween = new TimelineLite({ paused: true });   

  const animate = () => {
    myTween.to(navbar.current, 0.07, { x: "100" }).play()
  }

  return (
    <div className="nav-main" ref={navbar}>
      ...
    </div>
  )
}
like image 119
Asaf Aviv Avatar answered Sep 28 '22 05:09

Asaf Aviv