How to use the React useRef hook
The React useRef
hook accepts one argument as the initial value and returns a reference.
- The reference that is returned is an object with a special property, called
current
. ref.current
accesses the reference value.ref.current = newValue
updates the reference value.
We can use useRef
to store any value on its .current
property.
References versus state
- Persistence: The value of a reference is persisted (does not change) between component re-renders.
- No re-renders triggered: Updating a reference doesn’t trigger a component re-render.
useRef to access DOM elements
The useRef
hook is useful for accessing DOM elements. One use case for this is to add focus on an input field when a component mounts.
- Step 1: define the reference:
const inputRef = useRef(null)
- Step 2: assign the reference to the element:
<input ref={inputRef} />
Once a component is mounted, inputRef.current
will point to the DOM element. We can then manipulate this DOM element via the inputRef.current
reference.
export const UserForm = () => {
const inputRef = useRef(null);
// inputRef.current is null upon initial render
// There's no DOM structure created yet
console.log("inputRef is", inputRef.current);
// access useRef references inside useEffect
useEffect(() => {
inputRef?.current?.focus();
}, []);
return (
<div>
<label htmlFor="username">Username</label>
<input id="username" ref={inputRef} type="text" />
</div>
);
};
It is important to note that useRef
references must be referenced and used only once the DOM structure has been mounted. The useEffect
hook allows us to run code once the DOM structure has been created.
The first parameter passed to useEffect
is a function containing the code we want to run after the DOM is mounted for this component. The second parameter is an empty array []
, which tells useEffect
to run only once, after the component first renders. Not including the empty array would have useEffect
run after every component render, that is, the initial render and every re-render. This is not what we need for this example, and it is also more expensive performance-wise.
Managing state with useRef
The useRef
hook can be used as a stateful React hook. We can use the useRef
hook to manage component state without having to trigger a component re-render like useState
does.
const Counter = () => {
const countRef = useRef(0);
const handleClick = () => {
countRef.current++;
console.log(countRef.current);
};
return (
<>
<h1>Count: {countRef.current}</h1>
<button onClick={handleClick}>Click</button>
</>
);
};
When clicking the button, the current
property of countRef
is incremented by 1 and the result of this is correctly logged to the screen. The value of countRef.current
will be persisted no matter how many times this component re-renders due to prop or state changes.
Even if the current
property of countRef
has its value updated on every click, the component will not show the updated value in the HTML output of Count: {countRef.current}
. It will continue displaying the initial value of 0
. This is because useRef
does not trigger the re-rendering of a component. If a component does not re-render, it will not be able to display updates to values that occurred after its initial render to the screen.
Conclusion
Let's review some important useRef
lessons that we learned in this article.
useRef
references can access DOM elements.- The value of a a
useRef
reference is persisted across component re-renderings. - Updating a reference with
ref.current = newValue
, is not like updating state withuseState
, it does not trigger a component re-render.