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!
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.
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.
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.
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.
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>
)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With