useRef and useEffect: DOM Interactions
We use Ref when you want to track something and update it without triggering a rerender. If you want to trigger a rerender you can just use state instead.
Another specific use case for useRef()
is when you want to change DOM nodes and need a way to refer to them specifically. React doesn't really create DOM nodes until the render phase, so if you need to refer to them in your components, you need to provide a reference, or useRef()
.
In this example, we want to use a package called VanillaTilt
to add some effects to a div
in our code. We can define a variable called tiltRef
and assign it to React.useRef()
. This creates a generic ref which we can reuse later.
The ref is an object, whose sole attribute at initialization is current
. Thus, tiltRef.current
is the current value of that ref.
In our return function, we can add ref={tiltRef}
to the div
of interest so that way we're closing the loop.
Once this is all set up, we can do whatever we want with the ref. In this case, we use the VanillaTilt
package to add some effects to our div, and we use a useEffect
for this to allow us to interact with the DOM node.
The result is as follows:
// useRef and useEffect: DOM interaction
// http://localhost:3000/isolated/exercise/05.js
import React from 'react'
// eslint-disable-next-line no-unused-vars
import VanillaTilt from 'vanilla-tilt'
function Tilt({children}) {
const tiltRef = React.useRef()
React.useEffect(() => {
const tiltNode = tiltRef.current
VanillaTilt.init(tiltNode, {
max: 25,
speed: 400,
glare: true,
'max-glare': 0.5,
})
return () => tiltNode.vanillaTilt.destroy()
}, [])
return (
<div className="tilt-root" ref={tiltRef}>
<div className="tilt-child">{children}</div>
</div>
)
}
function App() {
return (
<Tilt>
<div className="totally-centered">vanilla-tilt.js</div>
</Tilt>
)
}
export default App
One thing to note: the return function in the useEffect
is a destroy function call. This is a cleanup function that gets called when the component is unmounted.
The reason we need this is to avoid memory leaks. That would mean that there is code that is running long after its relevant. Common cases where that may arise is when a HTTP call subscribes to an API or to some event, and does not unsubscribe after the user is done using the feature.