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.querySelector
orgetElementById
. - 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:
inputRef
is a reference to the input element.- When the button is clicked, the
focusInput
function 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:
prevSecondsRef
stores the previous value ofseconds
.- The
useEffect
hook updates theprevSecondsRef.current
value wheneverseconds
changes, 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.current
stores 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:
useRef
can help avoid unnecessary re-renders that might be triggered by usinguseState
when the state doesn’t actually need to affect the UI.