Published on 12.5.2019
React hooks have brought a new way to work with state, lifecycle methods, and context in functional components, making code more concise and easier to manage. Among these hooks, useRef
is one of the lesser-known gems. While it doesn’t directly cause re-renders like useState
, it plays a vital role when you need to persist values across renders or directly interact with DOM elements.
In this tutorial, we’ll explore when and how to use the useRef
hook. You’ll discover how it can simplify managing focus, tracking values over renders, and manipulating DOM elements.
What Is useRef
?
The useRef
hook returns a mutable object called a ref. This object has a .current
property that can store any mutable value, including DOM nodes or arbitrary data. The key here is that useRef
does not trigger a re-render when its value is updated, which is what makes it so powerful.
While useState
triggers a component re-render when the state changes, useRef
allows us to update its value without re-rendering the component. This makes useRef
perfect for cases like managing focus or tracking values that don’t need to cause a re-render.
When to Use useRef
1. Managing Focus
In React, managing focus programmatically (e.g., when you want an input field to gain focus automatically when the page loads) can be tricky, especially if you’re dealing with multiple renders. Instead of using a lifecycle method to do this, useRef
can help manage focus without the need for extra re-renders.
Example: Automatically Focus on an Input Field
import React, { useEffect, useRef } from 'react';
function FocusInput() {
const inputRef = useRef();
useEffect(() => {
// Focus the input element on mount
inputRef.current.focus();
}, []);
return <input ref={inputRef} />;
}
export default FocusInput;
Here, the useRef
hook stores a reference to the input element, and when the component mounts, useEffect
sets the focus to that input field. This all happens without triggering a re-render, ensuring smooth behavior.
2. Tracking Values Over Renders
Sometimes, you might need to store values between renders but don’t want to trigger a re-render when the value changes. useRef
can be used to hold onto any mutable value that should persist across renders.
Example: Tracking the Previous Value of a State
import React, { useState, useEffect, useRef } from 'react';
function Counter() {
const [count, setCount] = useState(0);
const prevCountRef = useRef();
useEffect(() => {
prevCountRef.current = count; // Store the previous count
}, [count]);
return (
<div>
<h1>Current Count: {count}</h1>
<h2>Previous Count: {prevCountRef.current}</h2>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
export default Counter;
In this example, we use useRef
to store the previous count, and it’s updated on every render. The value in prevCountRef.current
doesn’t cause a re-render, allowing you to track changes without impacting performance.
3. Accessing DOM Elements Directly
One of the most common uses for useRef
is storing a reference to a DOM element. This allows you to manipulate or interact with the DOM directly, such as setting focus, measuring an element, or playing a video. This method is generally used when you need direct access to the DOM rather than relying on React to manage the UI updates.
Example: Accessing a DOM Node for Animation
import React, { useRef } from 'react';
function BoxAnimation() {
const boxRef = useRef();
const moveBox = () => {
boxRef.current.style.transform = 'translateX(100px)';
};
return (
<div>
<div ref={boxRef} style={{ width: '100px', height: '100px', backgroundColor: 'red' }}></div>
<button onClick={moveBox}>Move Box</button>
</div>
);
}
export default BoxAnimation;
In this case, useRef
is used to directly manipulate the DOM node of the red box, and when the button is clicked, we change its position using inline styles. The component doesn’t re-render when the box moves because useRef
doesn’t trigger a re-render on updates.
How to Use useRef
Using useRef
is quite simple and doesn’t require much boilerplate. Here’s the basic syntax:
const myRef = useRef(initialValue);
initialValue
: The initial value you want the ref to have. It can be anything—null
, an object, a DOM element, etc.myRef.current
: The actual value or reference is accessed via.current
.
Example: Basic Usage
import React, { useRef } from 'react';
function MyComponent() {
const myRef = useRef();
const handleClick = () => {
console.log(myRef.current); // Logs the DOM element or value stored in the ref
};
return (
<div>
<button ref={myRef} onClick={handleClick}>Click Me</button>
</div>
);
}
export default MyComponent;
Conclusion
useRef
is a powerful and flexible hook that lets you manage DOM references and persist values across renders without causing unnecessary re-renders. While useState
is perfect for managing state that affects rendering, useRef
is the go-to solution when you need to handle things like focus management, tracking previous values, and direct DOM manipulation.
In this post, we’ve looked at when to use useRef
and how to integrate it into your React components for cleaner, more efficient code. Whether you’re automating focus or tracking non-UI state, useRef
is a must-know tool in the React ecosystem.