The useRef hook is a versatile hook in React that allows you to persist values across renders without triggering re-renders. It is commonly used for accessing DOM elements directly or storing mutable values that do not require re-rendering when updated.
1. What is the useRef Hook?
The useRef hook returns a mutable object with a .current property. This object persists across renders, and it doesn’t cause a re-render when its value changes. It’s mainly used for:
- Accessing DOM elements: Directly referencing DOM nodes without using
document.querySelectororgetElementById. - Storing mutable values: Keeping track of values (like previous state, timers, or counters) that don’t trigger a re-render when updated.
2. Basic Syntax of useRef
const myRef = useRef(initialValue);
initialValue: The value that you want the ref to be initialized with (optional). If not provided, it defaults tonull.
The myRef object returned by useRef contains a single property .current, which can hold any value you want.
3. Accessing DOM Elements
One of the most common uses of useRef is to reference DOM elements directly without causing re-renders. This can be useful when you need to focus an input field, measure its size, or perform other DOM manipulations.
Example: Accessing DOM Elements
import React, { useRef } from 'react';
function FocusInput() {
const inputRef = useRef();
const focusInput = () => {
inputRef.current.focus(); // Focuses the input element directly
};
return (
<div>
<input ref={inputRef} type="text" />
<button onClick={focusInput}>Focus the input</button>
</div>
);
}
export default FocusInput;
In this example:
inputRefis a reference to the input element.- When the button is clicked, the
focusInputfunction callsinputRef.current.focus(), focusing the input field without triggering a re-render.
4. Storing Mutable Values
You can also use useRef to store mutable values that don’t require re-renders. This is useful for keeping track of previous state, interval IDs, or any other value that should persist across renders but not trigger a re-render.
Example: Storing Mutable Values
import React, { useState, useEffect, useRef } from 'react';
function Timer() {
const [seconds, setSeconds] = useState(0);
const prevSecondsRef = useRef();
useEffect(() => {
prevSecondsRef.current = seconds;
}, [seconds]);
return (
<div>
<p>Current Seconds: {seconds}</p>
<p>Previous Seconds: {prevSecondsRef.current}</p>
<button onClick={() => setSeconds(seconds + 1)}>Increment</button>
</div>
);
}
export default Timer;
In this example:
prevSecondsRefstores the previous value ofseconds.- The
useEffecthook updates theprevSecondsRef.currentvalue wheneversecondschanges, allowing you to track the previous value without causing a re-render.
5. useRef vs. useState
While both useRef and useState can hold data, they behave differently:
useState: Triggers a re-render when the value changes.useRef: Does not trigger a re-render when the value changes.
Use useRef when you want to keep track of values across renders, but you don’t need React to re-render the component when the value changes. Use useState when the state change should trigger a re-render of the component.
6. useRef for Timer or Interval IDs
When you need to store references to timers or intervals, useRef is perfect because it allows you to access and clear timers or intervals without causing re-renders.
Example: Storing Interval ID
import React, { useEffect, useRef } from 'react';
function Stopwatch() {
const intervalRef = useRef(null);
const [seconds, setSeconds] = useState(0);
useEffect(() => {
if (intervalRef.current) {
clearInterval(intervalRef.current);
}
}, []);
const startTimer = () => {
intervalRef.current = setInterval(() => {
setSeconds(prev => prev + 1);
}, 1000);
};
const stopTimer = () => {
clearInterval(intervalRef.current);
};
return (
<div>
<p>Time: {seconds}s</p>
<button onClick={startTimer}>Start</button>
<button onClick={stopTimer}>Stop</button>
</div>
);
}
export default Stopwatch;
In this example:
intervalRef.currentstores the ID of the interval, which allows you to clear it when needed, preventing memory leaks.
7. When to Use useRef
- Accessing DOM Elements: When you need to directly manipulate or access a DOM element (e.g., focusing an input, scrolling, measuring the size).
- Storing Mutable Values: When you want to keep track of values that don’t need to trigger re-renders (e.g., previous state, timers, interval IDs).
- Performance Optimization:
useRefcan help avoid unnecessary re-renders that might be triggered by usinguseStatewhen the state doesn’t actually need to affect the UI.
