WTF is Up with Refs?
A friend of mine who was trying to write custom hooks with useRef
mentioned that ref
s were generally kind of confusing to him. After chatting through the things he wasn’t clear on, I realized that there were a few key concepts that aren’t necessarily obvious, but that give you the fundamental understanding to build on when using ref
s in other contexts:
Refs are just plain JavaScript objects - not special React things
Really. I promise. They’re just simple JS objects that have a current
key that can be set to any value. They’re basically just {current: foo}
. If you notice, there’s nothing particularly exciting or React-specific about {current: foo}
.
When passed as a prop, React sets ref.current to the new DOM nodes
While ref
s themselves aren’t exciting or special, React uses ref
s for React-specific behavior: if you pass in ref={myRef}
as a prop to a React component, React will make sure that myRef.current
will always return the DOM node of that element. It might be more complicated (I haven’t looked it up) but my mental model of Reactworld is:
- after mounting the component after the first render, set
ref.current = element
- if a new element is created as part of rerendering, update
ref.current
to the new element - after unmounting, set
ref.current = null
Updating a ref doesn’t trigger a rerender
State is what you should use if data changing should trigger a rerender. Refs are used when you need to keep a piece of mutable data across the entire lifecycle of the component, but that isn’t a part of the data-rendering cycle. In class components, this is usually maintained as just an instance variable; in hook land, useRef
is the way to go.
If you understand these three things about ref
s, then the useRef
hook starts to make a lot more sense. This knowledge is a prerequisite for my next post, where we’ll talk about how to design custom hooks that use ref
s, and how to avoid some common pitfalls.