When you want a component to “remember” some information,
→ don’t want trigger new renders
⇒ use a *ref*
(ref to your component by importing the useRef
Hook from React)
useRef
returns an object like this
const ref = useRef(0);
{
current: 0 // The value you passed to useRef
}
⇒ pass the initial value that you want to reference as the only argument.
You can access the current value of that ref through the ref.current
property. This value is intentionally mutable, meaning you can both read and write to it. It’s like a secret pocket of your component that React doesn’t track. (This is what makes it an “escape hatch” from React’s one-way data flow—more on that below!)
escape hatch
” you won’t need often.Here’s how state and refs compare:
refs | state |
---|---|
useRef(initialValue) returns { current: initialValue } |
useState(initialValue) returns the current value of a state variable and a state setter function ( [value, setValue] ) |
Doesn’t trigger re-render when you change it. | Triggers re-render when you change it. |
Mutable—you can modify and update current ’s value outside of the rendering process. |
“Immutable”—you must use the state setting function to modify state variables to queue a re-render. |
You shouldn’t read (or write) the current value during rendering. |
You can read state at any time. However, each render has its own snapshot of state which does not change. |
⇒ ref.current
during render leads to unreliable code. (never re-render)
in principle useRef
could be implemented on top of useState
.
You can imagine that inside of React, useRef
is implemented like this:
// Inside of React
function useRef(initialValue) {
const [ref, unused] = useState({ current: initialValue });
return ref;
}
the first render, useRef
returns { current: initialValue }
.
<aside> 💡 Note how the state setter is unused in this example.
⇒ It is unnecessary because useRef
always needs to return the same object!
</aside>